# New
function myNew(Con, args){
let obj = {}; // const obj = Object.create({});
Object.setPrototypeOf(obj, Con.prototype); //obj.__prototype__ = con.prototype;
let result = Con.call(obj, args);
// 在构造函数有返回值的情况进行判断
return typeof result === 'object'? result : obj;
}
1
2
3
4
5
6
7
2
3
4
5
6
7
Object.create({})
和new Object()
的区别:两者都是创建空对象,但是 new 创建出的空对象会绑定 Object 的 prototype 原型对象,但是Object.create({})
的空对象是没有任何属性的。
# Call
- 为 context 扩展一个属性,将原函数指向该属性。
- 将其他所有参数传递给这个新属性(函数),返回运行结果。
Function.prototype.myCall = function(context, ...args){
//context存在 默认window对象
context = context && typeof context === 'object'? context : window;
//防止覆盖原属性
const key = Symbol();
//this为方法
context[key] = this;
const result = context[key](...args);
delete context[key];
return result;
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# Apply
Function.prototype.myApply = function(context, args = []){
context = context && typeof context === 'object'? context : window;
const key = Symbol();
context[key] = this;
const result = context[key](...args);
delete context[key];
return result;
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# Bind
- 输入:接受一个或者多个参数,第一个是要绑定的上下文,额外参数当作绑定函数的前置参数。
- 输出:返回原函数的拷贝,即返回一个函数,这个函数具备原函数的功能.
- 实现:利用闭包和
call
。
Function.prototype.myBind = function(context, ...args){
let self = this;
let fn = function(...args2){
self.apply(this instanceof fn? this : context, [...args, ...args2]);
}
fn.prototype = object(self.prototype); //保护
return fn;
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# that = this
var a = {
b : function(){
var func = function(){
console.log(this.c);
}
func();
},
c : 'Hello!'
}
a.b();
//undefined
//this指向b
var a = {
b : function(){
var that = this;
var func = function(){
console.log(that.c);
}
func();
},
c : 'Hello!'
}
a.b();
//Hello!
//可以通过赋值的方式将this赋值给that
var a = {
b : function(){
var func = function(){
console.log(this.c);
}.bind(this);
func();
},
c : 'Hello!'
}
a.b();
//Hello!
var a = {
b : function(){
var func = function(){
console.log(this.c);
}
func.bind(this)();
},
c : 'Hello!'
}
a.b();
//Hello!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 函数柯里化
柯里化(Currying)又称部分求值,是分步处理参数的过程。currying的函数首先会接受一些参数,接受了这些参数之后,该函数不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正求值的时候,之前传入的所有参数都会被一次性用于求值。
function f(y, z){
return this.x + y + z;
}
var m = f.bind({x : 1}, 2);
console.log(m(3));
//6
1
2
3
4
5
6
2
3
4
5
6
# Promise
实现以下 Promise 使用:
const p1 = new Promise((resolve, reject) => {
console.log('create a promise');
resolve('成功了');
})
1
2
3
4
2
3
4
通过IIFE(立即执行函数)实现
const MyPromise = (function(){
const PromiseStatus = Symbol('PromiseStatus'),
PromiseValue = Symbol('PromiseValue');
const _PENDING = 'pending';
const _FULFILLED = 'fulfilled';
const _REJECTED = 'rejected';
const fulFilledList = Symbol('fulFilledList'),
rejectedList = Symbol('rejectedList');
let that = null;
const settleHandler = (_status, handler, queue) => {
if(that[PromiseStatus] === _status){
setTimeout(() => handler(that[PromiseValue]), 0);
}else{
queue.push(handler);
}
}
const changePromiseStatus = (_status, _result) => {
//Promise的状态一旦改变就不可以进行逆转, 所以我们必须确定当前阶段不是已决
if( that[PromiseStatus] != _PENDING) return;
that[PromiseStatus] = _status;
that[PromiseValue] = _result;
if(that[PromiseStatus] == _FULFILLED){
that.fulFilledList.forEach((ele) => { ele(that[PromiseValue]); });
}else{
that.rejectedList.forEach((ele) => { ele(that[PromiseValue]); });
}
}
const resolve = _data => {
changePromiseStatus(_FULFILLED, _data);
}
const reject = _error => {
changePromiseStatus(_REJECTED, _error);
}
return class MyPromise {
constructor(executor){
that = this;
this[PromiseStatus] = _PENDING;
this[PromiseValue] = undefined;
this[fulFilledList] = [];
this[rejectedList] = [];
try{
executor(resolve, reject);
}
// 如果我们在executor中报错, 则会直接触发reject从而进入rejected状态
catch(err){
reject(err);
}
}
then = (thenable, catchable) => {
settleHandler(_FULFILLED, thenable, this[fulFilledList]);
//a() && b() 如果 a 执行成功返回 true 则执行 b 返回 b 结果的值
typeof catchable === 'function' && this.catch(catchable);
}
catch = catchable => {
settleHandler(_REJECTED, catchable, this[rejectedList]);
}
}
})();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# Promise.all
function promiseAll(promises){
if(!Array.isArray(promises)){
throw new Error("Params must be an array!");
}
return new Promise((resolve, reject) => {
let asyncLength = promises.length;
let count = 0;
let resArray = new Array(asyncLength);
promises.forEach((item, index) => {
Promise.resolve(item)
.then((value) => {
count++;
resArray[index] = value;
if(count==asyncLength){
resolve(resArray);
}
})
.catch((error) => {
reject(error);
})
})
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Promise.race
function promiseRace(promises){
if(!Array.isArray(promises)){
throw new Error("Params must be an array!");
}
return new Promise((resolve, reject) => {
promises.forEach((item) => {
Promise.resolve(item)
.then((value) => {
resolve(value);
})
.catch((error) => {
reject(error);
})
})
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# async/await
Generator
缺陷:
- 函数外部无法捕获异常
- 多个 yield 会导致调试困难
async
函数对 Generator
函数改进如下:
- 内置执行器
- 更好的语义
- 更广的适用性
- 返回值是 Promise
async/await
做的事情就是将Generator
函数转换成Promise
。说白了,async 函数就是 Generator 函数的语法糖,await 命令就是内部 then 命令的语法糖。