[路飞]每日一答:手动实现 call , bind , apply

191 阅读2分钟

手动实现 call , bind , apply

这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。

call

call() 方法是预定义的 JavaScript 方法。它可以用来调用所有者对象作为参数的方法。

简单地说:通过 call(),你能够使用属于另一个对象的方法。

call 的使用

const p = {
  getName: function () {
    return this.name
  }
}

const p1 = {
  name: 'i am p1',
}

const p2 = {
  name: 'i am p2',

}

console.log(p.getName.call(p1)) // i am p1
console.log(p.getName.call(p2)) // i am p2

上述代码中, 对象 p1p2 是没有 getName 方法的,但是通过 call函数,使得 p1p2能够调用 getName方法。

重写 call

不难发现,实际上 call函数做了两件事:

  • 修改了 this 指向

  • 调用了 "调用 call 的函数"

所以,实现 call 的底层就是完成这两件事情。

1.在 Funtion 原型链上添加 myCall 方法,这样方便我们在 function 后调用自定义的 call 方法:

Function.prototype.mycall = function (obj) {
 
};

2.在参数上挂载该方法

mycall 方法传入的 obj 就是我们的主体对象,即调用者,也就是上述例子的 p1 , p2。他们本身没有 getName 方法,所以我们第一步是要给对象挂载上对应方法。这个对应方法,实际上就是 Function 原型链对象,即 this

 Function.prototype.mycall = function (obj) {
  obj.fn = this; // 此时this就是函数fn, 挂载方法
};

3.执行挂载方法,并保存结果

Function.prototype.mycall = function (obj) {
  obj.fn = this; // 此时this就是函数fn, 挂载方法
  const res = obj.fn(); // 执行fn,保存结果 res
 
};

4.删除挂载方法,并返回结果

Function.prototype.mycall = function (obj) {
  obj.fn = this; // 此时this就是函数fn, 挂载方法
  const res = obj.fn(); // 执行fn
  delete obj.fn; //删除fn
  return res
};

5.接受入参

Function.prototype.mycall = function (obj, ...args) {
  obj.fn = this; // 此时this就是函数fn, 挂载方法
  const res = obj.fn(...args); // 执行fn
  delete obj.fn; //删除fn
  return res
};

这样一来就实现了 call函数。

测试

const p = {
  getName: function () {
    return this.name
  }
}

const p1 = {
  name: 'i am p1',
}

const p2 = {
  name: 'i am p2',

}

Function.prototype.mycall = function (obj, ...args) {
  obj.fn = this; // 此时this就是函数fn, 挂载方法
  const res = obj.fn(...args); // 执行fn
  delete obj.fn; //删除fn
  return res
};

// console.log(p.getName.mycall(p1)) // i am p1
console.log(p.getName.mycall(p1))

apply

apply 和 call 函数的差别在于参数, call 用来接收多个参数, call 用来接收数组,所以我们可以在 call 的实现基础上去实现 apply

Function.prototype.myapply = function (obj, args) {
  return this.call(obj, ...args)
}

bind

bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值。

总结来说就是: bind返回函数的拷贝,并指定了函数的this指向,保存了函数的参数。

首先,bind 返回的是一个 函数,其次,这个函数的参数被保存下来了,让 obj 去调用。

Function.prototype.mybind = function (obj, ...args) {
  const func = this;
  return function F() { // 返回一个函数
    return func.apply(obj, [...args, ...arguments]); 
  };
}