手动实现 [ 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. 原理:普通函数的 this 指向调用者,改变调用者,即改变 this 指向

  2. 功能实现


     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  }
  3. 完善:允许第一个参数是任意值


     1   function  myCall(_this, ...arg) {  2       //  _this 允许传任意值 
     3  
     4       if  (_this ===  null  || _this === undefined) {  5          _this = global;  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. 原理:复用 myCall

  2. 实现


     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

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

  2. 实现


     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));

六、结尾

高阶层的 api 并非一步到位,它们的巧妙构思也是从低阶层的 api,一步步演化而来

标签: Javascript

添加新评论