zoukankan      html  css  js  c++  java
  • 关于call、apply和bind,请看这篇

    call

    func.call(context, arg1, arg2, ...)

    参数说明:
      context :在 func函数运行时指定的this值,当第一个参数为null、undefined的时候,默认指向window。
      arg1, arg2:…指定的参数列表。
    返回值:
      使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回undefined。


    apply(与call相似,只是参数不同而已)

    func.apply(context, arr)

    参数说明:
      context :在 func函数运行时指定的this值,当第一个参数为null、undefined的时候,默认指向window。
      arr 一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。


    bind

    func.bind(context, arg1, arg2, ...)

    参数说明:
      context :在 func函数运行时指定的this值,当第一个参数为null、undefined的时候,默认指向window。
      arg1, arg2:…指定的参数列表。
    返回值:
      返回一个原函数的拷贝,并拥有指定的this值和初始参数。

    例如:

      var name = '小王', age = 17;
        var obj = {
            name: '小张',
            age: this.age,
            myFun: function(fm, t) {
                console.log(this.name + ' 年龄' + this.age, ' 来自' + fm + '去往' + t);
            }
        }
        var db = {
            name: '德玛',
            age: 99
        }
      // 以下将obj的myFun方法应用到db对象上
        obj.myFun.call(db,'成都','上海');     // 德玛 年龄 99  来自 成都去往上海
        obj.myFun.apply(db,['成都','上海']);      // 德玛 年龄 99  来自 成都去往上海  
        obj.myFun.bind(db,'成都','上海')();       // 德玛 年龄 99  来自 成都去往上海
        obj.myFun.bind(db,['成都','上海'])();   // 德玛 年龄 99  来自 成都, 上海去往 undefined

    区别

    1、都是用来改变函数的this对象的指向的,this指向他们的第一个参数。
    2、call跟apply的用法几乎一样,唯一的不同就是传递的参数不同,call只能一个参数一个参数的传入。
    apply则只支持传入一个数组,哪怕是一个参数也要是数组形式。最终调用函数时候这个数组会拆成一个个参数分别传入。
    3、bind方法是直接改变这个函数的this指向并且返回一个新的函数,之后再次调用这个函数的时候this都是指向bind绑定的第一个参数。bind传参方式跟call方法一致。
    4、如果第一个参数为null或undefined,则this值会自动指向全局对象(浏览器中就是window对象)。

    call/apply/bind的核心理念:借用方法。借助已实现的方法,改变方法中数据的this指向,减少重复代码,节省内存。

    手写call、apply和bind

    // 通过隐式绑定实现
    Function.prototype.call = function(context, ...args) {
      // 如果没有传或传的值为空对象 context指向window
      context = context || window;
      // 给context添加一个方法 指向this
      context.func = this;
    
      if (typeof context.func !== 'function') {
        throw new TypeError('call must be called on a function');
      }
      // 执行func
      let res = context.func(...args);
      // 删除方法,否则context就无缘无故多了个func
      delete context.func;
      return res;
    }
    Function.prototype.apply = function(context, args) {
      context = context || window;
      context.func = this;
    
      if (typeof context.func !== 'function') {
        throw new TypeError('apply must be called on a function');
      }
    
      let res = context.func(...args);
      delete context.func;
      return res;
    }
    Function.prototype.bind = function(context, ...bindArgs) {
      context = context || window;
      // func 为调用 bind 的原函数
      const func = this;
    
      if (typeof func !== 'function') {
        throw new TypeError('Bind must be called on a function');
      }
      // bind 返回一个绑定 this 的函数
      return function(...callArgs) {
        let args = bindArgs.concat(callArgs);
        if (this instanceof func) {
          // 意味着是通过 new 调用的 而 new 的优先级高于 bind
          return new func(...args);
        }
        return func.call(context, ...args);
      }
    }
  • 相关阅读:
    【洛谷3527】[POI2011] MET-Meteors(树状数组+整体二分)
    【洛谷1580】yyy loves Easter_Egg I(字符串处理题)
    【BZOJ4866】[YNOI2017] 由乃的商场之旅(莫队)
    【BZOJ4810】[YNOI2017] 由乃的玉米田(莫队+bitset)
    【洛谷1494】[国家集训队] 小Z的袜子(莫队)
    【BZOJ3668】[NOI2014] 起床困难综合症(位运算思想)
    【BZOJ3720】Gty的妹子树(主席树+时间分块)
    【BZOJ2427】[HAOI2010] 软件安装(缩点+树形DP)
    【洛谷3648】[APIO2014] 序列分割(斜率优化DP)
    动态规划专题(五)——斜率优化DP
  • 原文地址:https://www.cnblogs.com/fengyuexuan/p/12408624.html
Copyright © 2011-2022 走看看