抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

手撕 js 系列

1 手写还原简单 promise

简单还原,链式调用和 catch 没写
我认为的核心就是 then 函数那,初次调用如果是 pending 状态等待,就把传入的函数收集起来
等到调用 resolve 或者 reject 的时候,把收集来的函数再调用,核心就是延迟执行回调函数

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
class MyPromise {
state: 'pending' | 'fulfilled' | 'rejected' = 'pending';
result: any;
thenFuncs: Array<{ done: Function; fail?: Function }> = [];
constructor(func: (resolve: Function, reject?: Function) => void) {
try {
func(this.resolve, this.reject);
} catch (err) {
this.reject(err);
}
}

resolve = (arg: any) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.result = arg;
queueMicrotask(() => {
this.thenFuncs.forEach(({ done }) => done(this.result));
this.thenFuncs = [];
});
}
};
reject = (arg: any) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.result = arg;
queueMicrotask(() => {
this.thenFuncs.forEach(({ fail }) => fail && fail(this.result));
this.thenFuncs = [];
});
}
};
then = (done: (res: any) => void, fail?: (res: any) => void) => {
if (this.state === 'pending') {
this.thenFuncs.push({ done: done, fail: fail });
}

if (this.state === 'fulfilled') {
queueMicrotask(() => {
done(this.result);
});
}

if (this.state === 'rejected') {
queueMicrotask(() => {
if (fail) fail(this.result);
});
}
};
}

console.log(1);

let my = new MyPromise((resolve, reject) => {
console.log(2);
setTimeout(() => {
resolve(3);
}, 1000);
});
my.then((res) => {
console.log(res);
});

instanceof

理解 new 的时候发生什么
简单讲就是,构造函数有原型链指向这个构造函数的原型对象(这玩意就是构造函数写的一堆属性之类的)
new 出来的对象也会有原型链指向那个原型对象

1
2
3
4
5
6
7
8
function myInstanceof(obj, constructor) {
let proto = Object.getPrototypeOf(obj);
while (proto) {
if (proto === constructor.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
return false;
}

typeof

直接用Object.prototype.toString.call()实现得了

1
2
3
4
5
function myTypeof(value) {
const typeStr = Object.prototype.toString.call(value);
// 会形如[object Type],所以取那个type就行了
return typeStr.slice(8, -1).toLowerCase();
}

深拷贝 deepClone

要处理很多情况,weakmap 处理循环引用,递归解决

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
function deepClone(value, hash = new WeakMap()) {
const typeStr = Object.prototype.toString.call(value);
if (typeStr === '[object Null]' || typeStr === '[object Undefined]' || typeStr === '[object String]' || typeStr === '[object Number]' || typeStr === '[object Boolean]') {
return value;
}
if (typeStr === '[object Date]') return new Date(value);
if (typeStr === '[object RegExp]') return new RegExp(value);

if (hash.has(value)) {
return hash.get(value);
}

if (typeStr === '[object Set]') {
let newSet = new Set();
hash.set(value, newSet);
value.forEach((item) => {
newSet.add(deepClone(item, hash));
});
return newSet;
}
if (typeStr === '[object Map]') {
let newMap = new Map();
hash.set(value, newMap);
value.forEach((mapValue, mapKey) => {
newMap.set(deepClone(mapKey, hash), deepClone(mapValue, hash));
});
return newMap;
}

if (Array.isArray(value)) {
let newArray = [];
hash.set(value, newArray);
return value.map((item) => deepClone(item, hash));
}

if (typeStr === '[object Object]') {
let newObj = {};
hash.set(value, newObj);
for (let key of Object.keys(value)) {
newObj[key] = deepClone(value[key], hash);
}
return newObj;
}

return value;
}

手写 new

创建一个空对象然后设置成构成函数的原型

1
2
3
4
5
6
7
function myNew(constructor, ...args) {
let obj = {};
Object.setPrototypeOf(obj, constructor.prototype);
let result = constructor.apply(obj, args);
if (typeof result === 'object' || typeof result === 'function') return result;
return obj;
}

评论