bind,call,apply源码仿写

重源码!bind的源码实现

bind 用法/特点

1 函数A调用bind方法时,需要传递的参数O, x, y, z, ···;
2 返回新的函数B;
3 函数B在执行的时候,具体的功能实际上还是使用的A,只不过this指向变成了O || window ;
4 函数B在执行的时候,传递的参数会拼接到x, y, z,···后面,一并传给A执行 ;
5 new B() 构造函数依旧是A, O不起任何作用 ;

  • call apply 直接执行;bind是返回一个函数,这个函数等待某个状态的触发才去执行

底层用call和apply来实现一下bind方法

1 这里 在Function原型上赋值了一个方法,实现了改变this指向功能;

 Function.prototype.newBind = function (target) {
        // target 改变返回函数执行的this指向
        var self = this;
        var f = function(){
            // 真正执行的其实是 self self = this
            return self.apply(target||window);            
        }
        return f;
    }

2 接下来实现了在绑定方法里this绑定对象以外再传参的功能

    Function.prototype.newBind = function (target) {
       // target 改变返回函数执行的this指向
       var self = this;
       var args = [].slice.call(arguments,1);
       var f = function(){
           // 真正执行的其实是 self self = this
           return self.apply(target||window,args);            
       }
       return f;
   }

3 再加入调用该newBind方法时,的传参功能

   Function.prototype.newBind = function (target) {
       // target 改变返回函数执行的this指向
       var self = this;
       var args = [].slice.call(arguments,1);
       var f = function(){
           var _arg = [].slice.call(arguments,0);
           // 真正执行的其实是 self self = this
           return self.apply(target||window,args.concat(_arg));            
       }
       return f;
   }

4 如果A调用newBind方法,在此基础上的new B()构造函数依旧是A,实现这个功能

     Function.prototype.newBind = function (target) {
       // target 改变返回函数执行的this指向
       var self = this;
       var args = [].slice.call(arguments,1);
       var temp = function(){};
       var f = function(){
           var _arg = [].slice.call(arguments,0);
           // 真正执行的其实是 self self = this
           return self.apply(this instanceof temp ? this : ( target||window),args.concat(_arg));            
       }
       temp.prototype = self.prototype;
       f.prototype =new temp();
       return f;
   }

call的源码实现

call用法、特点

call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。

发生的过程类似下面的情形

 const o = {
        a : 1,
        b : 2,
        add : function(c, d){
            return this.a + this.b + c + d;
        }
    }

1 给O对象添加一个add属性,这个时候this就指向了O;
2 O.add(5,7)得到的结果和add.call(O,5,7)相同;
3 call方法是立即调用,调用后方法不保存,所以仿写需要在方法执行后删除对象
上的这个方法。

  • 将函数设为对象的属性: o.fn = bar;
  • 执行该(函数)方法: o.fn() ;
  • 删除该方法: delete o.fn
 Function.prototype.es3Call = function (context) {
       var context = context || window;
       context.fn = this;
       var args = [];
       for(var i=1,len = arguments.length;i<len;i++){
           args.push('arguments['+ i +']');          
       }
       var result = eval('context.fn('+ args + ')');
           delete context.fn;
           return result;
   }

ES6 call的实现

  Function.prototype.es6Call = function (context) {
       var context = context || window;
       context.fn = this;
       var args = [];
       for(var i = 1, len = arguments.length; i<len;i++){
           args.push('arguments['+ i +']');
       }
       const result = context.fn(...args);
       delete context.fn;
       return result;
   }

apply 源码实现

apply和call区别在于apply第二个参数是Array,而call是将参数一个一个传入的。

Function.prototype.es3Apply = function (context,arr) {
      var context = context || window;
      context.fn = this;
      var result;
      if(!arr){
          result = context.fn();
      }else{
          var args = [];
          for(var i = 0,len = arr.length;i<len; i++){
              args.push('arr['+ i +']');
          } 
          result = eval('context.fn('+ args +')');         
      }
      delete context.fn;
      return result;
  }
 

基于es6的实现

 Function.prototype.es6Apply = function (context,arr) {
   var context = context || window;
   context.fn = this;
   var result;
   if (!arr) {
       result = context.fn();
   }else{
       if(!(arr instanceof Array)) throw new Error('params must be array');
        result = context.fn(...arr);
   }
   delete context.fn;
   return result;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值