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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: bind、call和apply都是用来改变函数中this的指向的方法。 bind方法会返回一个新的函数,这个新函数的this指向被绑定的对象,但不会立即执行。 call和apply方法都是立即执行函数,并且都会改变函数中this的指向。它们的区别在于传入参数的方式不同,call方法是将参数一个一个传入,而apply方法是将参数放在一个数组中传入。 举个例子: ``` var obj = { name: 'Tom' }; function sayHello(age) { console.log('Hello, my name is ' + this.name + ', I am ' + age + ' years old.'); } var newSayHello = sayHello.bind(obj); newSayHello(18); // Hello, my name is Tom, I am 18 years old. sayHello.call(obj, 18); // Hello, my name is Tom, I am 18 years old. sayHello.apply(obj, [18]); // Hello, my name is Tom, I am 18 years old. ``` 以上代码中,我们定义了一个对象obj和一个函数sayHello。使用bind方法将sayHello函数中的this指向obj,并返回一个新的函数newSayHello。使用call和apply方法直接调用sayHello函数,并将this指向obj,同时传入参数18。 ### 回答2: bind和call apply都是JavaScript中用来改变函数执行上下文的方法,但它们有些许区别。 bind方法会创建一个新函数,其this值会被绑定到指定的对象上。它接收一个参数,即想要将函数绑定到的对象。如果绑定的函数参数存在,则会将绑定函数的参数传递给原始函数,同时返回绑定后的新函数。如果绑定的函数没有参数,则直接返回一个绑定后的新函数。bind方法并不会立即调用函数,而是返回一个函数引用,需要手动调用函数才会执行。 call和apply则是直接调用函数,并且可以指定函数执行上下文。它们最主要的区别在于传递参数的方式不同。call方法接收的参数是一个参数列表,即需要传递给函数的参数直接列出来一个一个传递。apply方法接收的参数是一个数组,即需要传递给函数的参数通过数组的方式传递。另外,如果函数没有参数,那么使用call和apply的方式没有区别。 因此,如果我们想要在不同的上下文中调用函数,可以使用bind方法,在其他时候可以使用call和apply方法。同时,由于bind方法会创建新的函数引用,可能会占用一些内存空间,因此可考虑使用call和apply方法。 ### 回答3: bind、call和apply是JavaScript中三个非常重要的函数方法,它们都用于改变函数的this指向。虽然它们的作用类似,但是它们具体的使用方式有很大的不同。 bind()、call()和apply()都能够把一个函数的this指向指定为第一个参数中的对象,并且都可以传递多个参数给函数。具体差别如下: 1. bind():bind()方法常常用于多次调用同一函数,且该函数的this值不变。bind()方法会返回一个新函数,并且它的this值总是被指定为第一个参数。bind()方法的传参方式,与原函数相同,在调用时将参数以一个个单独的参数传入。 2. call():将具体的值,作为指定的this,传入并执行该函数。call()方法会在调用时执行指定函数,并且呈现出函数的this值为第一个参数的对象。call()方法的传参方式,将参数以一个个单独的参数传入。 3. apply():apply()的作用与call()类似,主要区别在于参数的传递方式,apply()会将参数直接传入数组。就是说,在调用apply()方法时,需要将需要绑定到this的对象作为第一个参数传入,第二个参数是一个数组、列表或类似数组的对象,该数组中的所有元素都将作为单独的参数传递给被调用的函数。 总之,bind()、call()和apply()都是用于改变函数的this指向,它们之间的区别主要在于传递参数的方式不同。在实际开发中,我们需要根据场景的需要选择不同的方法来使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值