call 、apply 以及 bind 的区别和用法 以及手写实现

163 阅读2分钟

call 、apply 以及 bind 的区别和用法 以及手写实现

手写实现 call、apply、bind

call 方法作用

调用一个对象的一个方法,以另一个对象替换当前对象。也就是说改变方法中 this 指向,第一个参数代表 this 指向的对象,后面紧跟的参数为函数原有的形参

const A = {
  name: '我是A对象的name',
  getName: function () {
    console.log(this.name);
  },
};
const B = {
  name: '我是B对象的name',
};
A.getName(); // //结果 我是A对象的name
A.getName.call(B); //结果 我是B对象的name
  1. 使用 call 改变了 A 对象中 getName 方法的 this 指向,使其指向了 B 对象
  2. fn.call(obj)可以看成 obj.fn(...args),这样 fn 中的 this 就指向了 obj
  3. 我们可以使用 call 方法,借助其他对象中存在的方法实现自己的功能,例如 es5 将伪数组转为真正的数组,new 关键字的实现也借助了 call 方法等

自定义 call 方法

const A = {
  name: '我是A对象的name',
  getName: function (a, b, c) {
    console.log(this.name, a + b + c);
  },
};
const B = {
  name: '我是B对象的name',
};
//call前面是fucntion函数,所以该方法需要添加到Function构造函数的原型对象上
Function.prototype.myCall = function (context, ...args) {
  if (typeof this !== 'function') {
    throw new Error(`${this} is not function`);
  }
  if (!context instanceof Object) {
    throw new Error(`${context} is not Object`);
  }
  //将函数绑定到对象上作为对象上的方法
  context.fn = this;
  //执行对象中的方法
  const result = context.fn(...args);
  //删除被绑定的方法
  delete context['fn'];
  return result;
};
A.getName.myCall(B, 1, 2, 3); //我是B对象的name 6
A.getName.call(B, 1, 2, 3); //我是B对象的name 6

apply 与 call 对比

功能相同,都是改变 this 指向

语法不同 apply 的语法:函数名.call(obj,[参数 1,参数 2,参数 3...])

apply 方法的使用

const A = {
  name: '我是A对象的name',
  getName: function (a, b, c) {
    console.log(this.name, a + b + c);
  },
};
const B = {
  name: '我是B对象的name',
};
A.getName.apply(B, [1, 2, 3]); //输出 我是B对象的name 6

自定义 apply 方法

const A = {
  name: '我是A对象的name',
  getName: function (a, b, c) {
    console.log(this.name, a + b + c);
  },
};
const B = {
  name: '我是B对象的name',
};
Function.prototype.myApply = function (context, args) {
  if (typeof this !== 'function') {
    throw new Error(`${this}is not function`);
  }
  if (!context instanceof Object) {
    throw new Error(`${context} is not Object`);
  }
  if (args && !Array.isArray(args)) {
    throw new Error(`${args} is not Array`);
  }
  context.fn = this;
  const result = context.fn(...args);
  return result;
};
A.getName.myApply(B, [1, 2, 3]); //输出 我是B对象的name 6

bind 与 apply 和 call 对比

  1. 功能相同,都是改变 this 指向
  2. 返回值不同,bind 会返回一个函数,我们需要调用这个返回值
  3. 入参与 call 相同

bind 方法的使用

const A = {
  name: '我是A对象的name',
  getName: function (a, b, c) {
    console.log(this.name, a + b + c);
  },
};

const B = {
  name: '我是B对象的name',
};
A.getName.bind(B)(
  1,
  2,
  3
) //输出 我是B对象的name 6
``;

自定义 bind 方法

const A = {
  name: '我是A对象的name',
  getName: function (a, b, c) {
    console.log(this.name, a + b + c);
  },
};

const B = {
  name: '我是B对象的name',
};
Function.prototype.myBind = function (context) {
  const self = this;
  if (typeof self !== 'function') {
    throw new Error(`${self}is not function`);
  }
  if (!context instanceof Object) {
    throw new Error(`${context} is not Object`);
  }
  //bin方法返回一个函数
  return function (...args) {
    context.fn = self;
    const result = context.fn(...args);
    delete context.fn;
    return result;
  };
};
A.getName.myBind(B)(1, 2, 3); //输出 我是B对象的name 6