# 手写实现 js 方法
# promise
// 先定义三个常量表示状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
// 新建 myPromise 类
class myPromise {
constructor(executor) {
// 储存状态的变量,初始值是 pending
this.status = PENDING;
// 成功之后的值
this.value = null;
// 失败之后的原因
this.reason = null;
// 更改成功后的状态
this.resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED; // 修改状态
this.value = value; // 保存成功后的值
// 判断 并 执行回调函数
while (this.onFulfilledCallback.length) {
this.onFulfilledCallback.shift()(value);
}
}
};
// 更改失败后的状态
this.reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED; // 修改状态
this.reason = reason; // 保存失败后的原因
// 判断 并 执行回调函数
while (this.onRejectedCallback.length) {
this.onRejectedCallback.shift()(reason);
}
}
};
// 存储成功回调函数
this.onFulfilledCallback = [];
// 存储失败回调函数
this.onRejectedCallback = [];
try {
// executor 是一个执行器,进入会立即执行
// 并传入resolve和reject方法
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
then(onFulfilled, onRejected) {
// if (this.status === FULFILLED) {
// onFulfilled(this.value);
// } else if (this.status === REJECTED) {
// onRejected(this.reason);
// } else if (this.status === PENDING) {
// // 等到执行成功失败函数的时候再传递
// this.onFulfilledCallback.push(onFulfilled);
// this.onRejectedCallback.push(onRejected);
// }
// 如果不传,就使用默认函数
const realOnFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
const realOnRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
// then 链式调用
const promise2 = new myPromise((resolve, reject) => {
const fulfilledMicrotask = () => {
// 创建一个微任务等待 promise2 完成初始化
queueMicrotask(() => {
try {
// 获取成功回调函数的执行结果
const x = realOnFulfilled(this.value);
// 传入 resolvePromise 集中处理
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
};
const rejectedMicrotask = () => {
// 创建一个微任务等待 promise2 完成初始化
queueMicrotask(() => {
try {
// 调用失败回调,并且把原因返回
const x = realOnRejected(this.reason);
// 传入 resolvePromise 集中处理
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
};
// 判断状态
if (this.status === FULFILLED) {
fulfilledMicrotask();
} else if (this.status === REJECTED) {
rejectedMicrotask();
} else if (this.status === PENDING) {
// 等待
// 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
// 等到执行成功失败函数的时候再传递
this.onFulfilledCallback.push(fulfilledMicrotask);
this.onRejectedCallback.push(rejectedMicrotask);
}
});
return promise2;
}
all(promises) {
if (!Array.isArray(promises)) {
throw new Error("promises must to be an array!!!");
}
return new myPromise(function (resolve, reject) {
let promiseNum = promises.length;
let resolvedCount = 0;
let resolveValues = new Array(promiseNum);
try {
for (let i = 0; i < promiseNum; i++) {
promises[i].then(function (value) {
resolveValues[i] = value;
if (++resolvedCount === promiseNum) {
resolve(resolveValues);
}
});
}
} catch (error) {
reject(error);
}
});
}
race(promises) {
if (!Array.isArray(promises)) {
throw new Error("promises must be an array!!!");
}
let resolved = false;
return new myPromise(function (resolve, reject) {
try {
promises.forEach((p) =>
p.then((data) => {
if (!resolved) {
resolved = true;
resolve(data);
}
})
);
} catch (error) {
reject(error);
}
});
}
}
function resolvePromise(promise2, x, resolve, reject) {
// 如果相等了,说明return的是自己,抛出类型错误并返回
if (promise2 === x) {
return reject(
new TypeError("Chaining cycle detected for promise #<Promise>")
);
}
// 判断x是不是 myPromise 实例对象
if (x instanceof myPromise) {
// 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected
// x.then(value => resolve(value), reason => reject(reason))
// 简化之后
x.then(resolve, reject);
} else {
// 普通值
resolve(x);
}
}
// 导出
// export default myPromise;
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# call apply bind
let Person = {
name: "Tom",
say(a, b) {
this.a = a;
this.b = b;
console.log(this);
console.log(`我叫${this.name}, a: ${this.a}, b: ${this.b}`);
}
};
// ----------------------------------------------------------------------------
/**
* call
* @param {*} ctx
* 1.ctx 存在就使用 ctx window
* 2.使用 Object(ctx) 将 ctx 转换成对象,并通过 ctx.fn 将 this 指向 ctx
* 3.循环参数,注意从 1 开始,第 0 个是上下文,后面才是我们需要的参数
* 4.将参数字符串 push 进 args
* 5.拿到结果返回前,删除掉 fn
*/
/* eslint-disable */
Function.prototype.myCall = function (ctx) {
ctx = ctx || window;
const fn = Symbol(); // Symbol属性来确定fn唯一。
const args = [...arguments].slice(1);
// console.log(this);
ctx[fn] = this; // this 是调用 call 的函数 f say() {}
const result = ctx[fn](...args);
delete ctx[fn];
return result;
};
// ----------------------------------------------------------------------------
let PersonA = {
name: "Tom A"
};
Person.say.myCall(PersonA, "A1", "A2");
// ----------------------------------------------------------------------------
/**
* apply
* @param {*} ctx
* @param {*} args
* 1.apply 无需循环参数列表,传入的 args 就是数组
* 2.但是 args 是可选参数,如果不传入的话,直接执行
*/
/* eslint-disable */
Function.prototype.myApply = function (ctx, args) {
ctx = ctx || window;
const fn = Symbol(); // Symbol属性来确定fn唯一。
ctx[fn] = this; // this 是调用 call 的函数 f say() {}
let result;
if (!args) {
// 判断 args 是否存在
result = ctx[fn]();
} else {
result = ctx[fn](...args);
}
delete ctx[fn];
return result;
};
// ----------------------------------------------------------------------------
let PersonB = {
name: "Tom B"
};
Person.say.myApply(PersonB, ["B1", "B2"]);
// ----------------------------------------------------------------------------
/**
* bind
* 1. 改变this指向
* 2. 接受参数列表、
* 3. return 一个函数
* 4. 遇到new这样优先级高于bind方法的时候,bind改变this指向会无效。
*/
/* eslint-disable */
Function.prototype.myBind = function (ctx) {
var self = this; // 因为之后要return一个函数,这里保存一下this防止混乱
var args = Array.prototype.slice.call(arguments, 1); // 获取参数
var fb = function () {
var bindArgs = Array.prototype.slice.call(arguments);
const target = this instanceof fb ? this : ctx;
return self.apply(target, args.concat(bindArgs));
};
var fn = function () {};
fn.prototype = this.prototype; // 让实例可以继承原型
fb.prototype = new fn();
return fb;
};
// ----------------------------------------------------------------------------
let PersonC = {
name: "Tom C"
};
const fnC = Person.say.myBind(PersonC, "C1");
fnC("C2");
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# New
/**
* new
* 1.Constructor 就是 new 时传入的第一个参数,剩余的 arguments 是其他的参数
* 2.使用obj.__proto__ = Constructor.prototype 继承原型上的方法
* 3.将剩余的 arguments 传给 Constructor ,绑定 this 指向为 obj,并执行
* 4.如果构造函数返回的是引用类型,直接返回该引用类型,否则返回 obj
*/
const myNew = function () {
let Constructor = Array.prototype.shift.call(arguments);
let obj = new Object();
obj.__proto__ = Constructor.prototype;
// console.log(Constructor, obj);
let res = Constructor.apply(obj, arguments);
return res instanceof Object ? res : obj;
};
function fun(a, b) {
this.a = a;
this.b = b;
this.c = function () {
console.log(this.a, this.b);
return this;
};
}
const test = myNew(fun, "A", "B");
console.log(test.c());
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
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
← 文件操作 deepAssign →