zoukankan      html  css  js  c++  java
  • call / apply / bind

    对于 call / apply / bind 来说,他们的首要目的是用于改变执行上下文的 this 指针。

    call / apply

    对 call / apply 的使用,一般都如下,用于改变执行环境的上下文。只是 call 接受的是一个一个的参数,而 apply 则是接受的是一个参数数组。

    const obj1 = {
      a: 1,
      myFunc(var1) {
        console.log(this.a + var1)
      }
    }
    const obj2 = {
      a: 2
    }
    
    const myFunc = obj1.myFunc
    
    myFunc(1)                 // NaN
    obj1.myFunc(1)            // 2
    myFunc.call(obj2, 1)      // 3
    myFunc.apply(obj2, [1])   // 3
    

    bind

    bind 是 ES2015 出的一个方法,也是用于改变函数内部的 this 指向。但不一样的是,bind 方法不是直接执行的,而是生成一个新的已被改变过的函数。

    const obj1 = {
      a: 1,
      myFunc(var1) {
        console.log(this.a + var1)
      }
    }
    const obj2 = {
      a: 2
    }
    
    const myFunc = obj1.myFunc
    const bindMyFunc1 = myFunc.bind(obj1)
    const bindMyFunc2 = myFunc.bind(obj2)
    
    myFunc(1)         // NaN
    bindMyFunc1(1)    // 2
    bindMyFunc2(1)    // 3
    

    通过上面的例子就可以看出来,bind 方法就可以生成一个新的 this 指向的 function。

    手动写 bind 函数

    仅仅作为简单实现的话,我们仅需要注意改变 this 指向和预置参数即可。

    function bind(fn, _this, ...args) {
      if(typeof fn !== 'function') {
        throw new Error('bind fn need to be function')
      }
      return function(...innerArgs) {
        return fn.apply(_this, [...args, ...innerArgs])
      }
    }
    

    当然这个手动实现的 bind 方法是只实现了最主要的功能,对函数的原型链和作为构造函数的方式都是没有考虑到的。这里可以参考 MSDN 的 polyfill 方法。

    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 fBound === true时,说明返回的fBound被当做new的构造函数调用
              return fToBind.apply(this instanceof fBound
                     ? 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;
      };
    }
    
  • 相关阅读:
    java DES转C#DES加密解密
    PIE SDK影像格式转换
    PIE SDK位深转换
    PIE SDK存储格式转换
    PIE SDK栅格生成等值线、面
    PIE SDK反距离权重插值算法
    PIE SDK克里金插值法
    PIE SDK热力图
    PIE SDK Alpha通道数据渲染
    PIE SDK 多数据源的复合数据集加载
  • 原文地址:https://www.cnblogs.com/YikaJ/p/10683142.html
Copyright © 2011-2022 走看看