call、apply 及 bind 函数

116 阅读2分钟

相关概念

bind 是返回对应函数,便于稍后调用;

apply 、call 则是立即调用。

在 javascript 中,call 和 applybind 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。
JavaScript 的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。

call

  • 第一个参数 : 设置this的指向,如果指定了 null 或者 undefined 则内部 this 指向 window
    其他参数 : 对应函数的参数
  • call的返回值就是函数的返回值
      
      let obj = {
        name: '小刚',
        say: function (...args) {
          console.log(this.name + 'say', args);
        },
      };

      let obj1 = {
        name: '小虽',
        say: function (...args) {
          console.log(this.name + 'say', args);
        },
      };
      
      let obj2 = {
        name: '小华',
        say: function (...args) {
          console.log(this.name + 'say',args);
        },
      };
      
      obj.say(1,2); // 小刚say [1, 2]
      obj.say.call(obj1, 1, 2); // 小虽say [1, 2]
      obj.say.call(obj2, 1, 2); // 小华say [1, 2]
      

apply

  • 第一个参数 : 设置函数内部this的指向

    第二个参数 : 是数组

  • call的返回值就是函数的返回值


      let obj = {
        name: '小刚',
        say: function (...args) {
          console.log(this.name + 'say', args);
        },
      };

      let obj1 = {
        name: '小虽',
        say: function (...args) {
          console.log(this.name + 'say', args);
        },
      };
      
      let obj2 = {
        name: '小华',
        say: function (...args) {
          console.log(this.name + 'say',args);
        },
      };
      
      function fn(...args){
          obj.say(...args); // 小刚say [1, 2]
          obj.say.apply(obj1, args); // 小虽say [1, 2]
          obj.say.apply(obj2, args); // 小华say [1, 2]
      
      }
      fn(1,2);

bind

  • bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。

  • 当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。

  • 一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。

    let obj = {
        name: '小刚',
        say: function (...args) {
          console.log(this.name + 'say', args);
        },
      };

      let obj1 = {
        name: '小虽',
        say: function (...args) {
          console.log(this.name + 'say', args);
        },
      };
      
      let obj2 = {
        name: '小华',
        say: function (...args) {
          console.log(this.name + 'say',args);
        },
      };
      
      function bindFn(...args){
          obj.say(...args); // 小刚say [1, 2]
          obj.say.bind(obj1, ...args)(); // 小虽say [1, 2]
          obj.say.bind(obj2, ...args)(); // 小华say [1, 2]
      
      }
      bindFn(1,2);

自定义实现

call

function myCall(context) {
  //判断一下
  if (typeof this !== 'function'){
    throw new TypeError('error')
  }
  //this指向,谁去执行去这个函数
  context = context || window;
  //要执行的函数
  context.fn = this;
  //取出参数
  const args = [...arguments].slice(1);
  //执行函数
  const result = context.fn(...args);
  //删除fn
  delete context.fn;
  return result;
}

apply

function myApply(context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error');
  }
  context = context || window;
  context.fn = this;
  var result;
  if (arguments[1]) {
    result = context.fn(...arguments[1]);
  } else {
    result = context.fn();
  }
  delete context.fn;
  return result;
}

bind

function  myBind(context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error')
    }
    const _this = this
    const args = [...arguments].slice(1)
    // 返回函数
    return function F() {
      // 1 判断是否用作构造函数
      if (this instanceof F) {
        return new _this(...args, ...arguments)
      }
      // 2 用作普通函数
      return _this.apply(context, args.concat(...arguments))
    }
}

var f1 = test.myBind(obj, 1)
var f= new f1(2)