手动实现call、apply、bind

先写一个骨架

 1 Object.assign(Function.prototype, {
 2     myCall,
 3     myApply,
 4     myBind,
 5 });
 6 
 7 function myCall(_this, ...arg) {}
 8 
 9 function myApply(_this, arg) {}
10 
11 function myBind(_this, ...arg1) {}

myCall

原理:改变调用者

 1 function myCall(_this, ...arg) {
 2     // 注意:
 3     // 1. 使用 Symbol 作为 key,避免造成意外覆盖
 4     // 2. 要有 return,否则原始函数的执行结果无法暴露
 5 
 6     const key = Symbol();
 7     _this[key] = this;
 8     const res = _this[key](...arg);
 9     delete _this[key];
10 
11     return res;
12 }

完善:允许第一个参数是任意值

 1 function myCall(_this, ...arg) {
 2     // _this 允许传任意值
 3 
 4     if (_this === null || _this === undefined) {
 5         return this(...arg); 6     }
 7 
 8     if (!(typeof _this == "object")) {
 9         _this = Object(_this);
10     }
11 
12     // 注意:
13     // 1. 使用 Symbol 作为 key,避免造成意外覆盖
14     // 2. 要有 return,否则原始函数的执行结果无法暴露
15 
16     const key = Symbol();
17     _this[key] = this;
18     const res = _this[key](...arg);
19     delete _this[key];
20 
21     return res;
22 }

myApply

1 function myApply(_this, arg) {
2     // apply 的第二个参数限定为数组;其它具备 iterator 的数据结构也行
3     if (!(arg instanceof Array)) {
4         throw new Error("Please enter an array");
5     }
6 
7     return this.myCall(_this, ...arg);
8 }

myBind

分析:原生 bind 返回一个绑定了 _this 和 部分参数的新函数

1 function myBind(_this, ...arg1) {
2     const target = this;
3 
4     function res(...arg2) {
5         return target.myApply(_this, [...arg1, ...arg2]);
6     }
7 
8     return res;
9 }

测试

设计一个比较好的测试,用更少的代码,测试更多的功能

1 function foo(a, b, c) {
2     return [this === obj, a, b, c];
3 }
4 
5 const obj = {};
6 
7 console.log(foo.myCall(obj, "myCall", 0, 1));
8 console.log(foo.myApply(obj, ["myApply", 0, 1]));
9 console.log(foo.myBind(obj, "myBind").myBind(null, 0)(1));

结尾

需要bind的人多了,也就有了bind

posted @ 2022-10-20 08:29  万物有序  阅读(60)  评论(0编辑  收藏  举报