美文网首页
call,apply,bind

call,apply,bind

作者: 夜舞暗澜_3ea2 | 来源:发表于2018-07-13 12:48 被阅读0次

    call是做什么用的?

    JS中使用原型思想。如果一个obj原型链上没有特定的方法,那么JS就不知道如何调用它。比如一个类数组对象(ex. HTMLCollection)就没有好用的数组方法。
    但是类数组对象与数组的结构几乎一致,为什么就不能使用数组的方法呢?
    所以JS给我们提供了一种方法,能够告诉JS,我们指定了obj像Array一样运作,例如Array.prototype.map.call(obj)

    查看示例:

    function Product(name, price) {
      this.name = name;
      this.price = price;
    }
    
    function Food(name, price) {
      Product.call(this, name, price);
      this.category = 'food';
    }
    
    console.log(new Food('cheese', 5).name);
    // expected output: "cheese"
    

    Food是没有name和price属性的。但是为了继承Product的一系列属性,Food在构造过程中call了Product的构造函数。
    看到了?这也是继承的一种方法。
    其实当我们调用对象上的方法时,写成obj.func(...args),其内部实现也是func.call(obj, ...args)

    语法:

    fun.call(thisArg, arg1, arg2, ...)
    

    call和apply的区别?

    根据MDN,两者只有一个区别,就是call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组

    刚才是fun.call(thisArg, arg1, arg2, ...)
    现在是fun.apply(thisArg, [arg1, arg2, ...])

    能看出来吗?就差这么一点。

    bind

    这里涉及到this的指向问题。当我们调用一个函数时,函数中的this会指向当前调用函数的对象
    bind()方法相当于创建一个新函数,不管调用这个函数的对象是谁,this都将会指向绑定的对象。
    Function.prototype.bind()-MDN

    语法:

    fun.bind(thisArg[, arg1[, arg2[, ...]]])
    

    还是看例子:

    var module = {
      x: 42,
      getX: function() {
        return this;
      }
    }
    
    var unboundGetX = module.getX;
    console.log(unboundGetX());
    // > [object Window]
    
    var boundGetX = unboundGetX.bind(module);
    console.log(boundGetX());
    /*
    > Object { x: 42, getX: function() {
        return this;
      } }
    */
    

    在不使用bind时,调用unboundGetX()方法的对象是window,所以this指向window。
    当用bind绑定module时,this重新指向了module。

    一些比较重要的补充:

    1. bind()函数在 ECMA-262 第五版才被加入;它可能无法在所有浏览器上运行。如果不能运行,可以在脚本开头加入腻子:

    if (!Function.prototype.bind) {
      Function.prototype.bind = function(oThis) {
        if (typeof this !== 'function') {
          // closest thing possible to the ECMAScript 5
          // internal IsCallable function
          throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
        }
    
        var aArgs   = Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            fNOP    = function() {},
            fBound  = function() {
              // this instanceof fNOP === true时,说明返回的fBound被当做new的构造函数调用
              return fToBind.apply(this instanceof fNOP
                     ? this
                     : oThis,
                     // 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
                     aArgs.concat(Array.prototype.slice.call(arguments)));
            };
    
        // 维护原型关系
        if (this.prototype) {
          // Function.prototype doesn't have a prototype property
          fNOP.prototype = this.prototype; 
        }
        // 下行的代码使fBound.prototype是fNOP的实例,因此
        // 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
        fBound.prototype = new fNOP();
    
        return fBound;
      };
    }
    

    你不用看懂,只要把这段代码贴到开头就好了。

    2. 匿名函数和箭头函数:

    匿名函数的this通常会指向全局window,这很适合使用bind做出改变。
    示例:

    var module = {
      x: 42
    }
    
    var unboundGetX = function(){return this};
    console.log(unboundGetX())
    // > [object Window]
    
    var boundGetX = function(){return this}.bind(module);
    console.log(boundGetX())
    // > Object { x: 42 }
    

    但是!箭头函数会默认做一个bind(this)的操作,也就是箭头函数是不能使用bind的

    var boundGetX = ()=>{return this}.bind(module);
    console.log(boundGetX())
    // Error: Unexpected token .
    

    相关文章

      网友评论

          本文标题:call,apply,bind

          本文链接:https://www.haomeiwen.com/subject/ekyjpftx.html