返回

手动实现call(), apply(), bind()

前端

为了更好地理解call(), apply()和bind()函数的原理,我们可以尝试手动实现这
三者的用法。

手动实现call(), apply(), bind()

1.回忆

call(), apply(), bind()都是内置的函数,其作用都是为了修改函数执行时的this指向 。当函数被调用时,this指向的是全局作用域 ,但是我们可以使用这三者中的任意一个来修改this指向,使之指向任何我们想要指向的对象。

2.call函数实现

接下来我们开始实现call函数。call函数主要有两个参数,第一个参数是this要指向的对象,第二个参数是参数列表。

Function.prototype.call = function (obj, ...args) {
  if (obj == null || obj == undefined) {
    obj = window;
  }
  obj.fn = this;
  let result = obj.fn(...args);
  delete obj.fn;
  return result;
};

3.apply函数实现

apply函数也主要有两个参数,第一个参数是this要指向的对象,第二个参数是参数列表,参数列表必须是以数组的形式书写的。

Function.prototype.apply = function (obj, args) {
  if (obj == null || obj == undefined) {
    obj = window;
  }
  obj.fn = this;
  let result = obj.fn(args);
  delete obj.fn;
  return result;
};

4.bind函数实现

bind函数主要有两个参数,第一个参数是this要指向的对象,第二个参数是参数列表,参数列表必须是以数组的形式书写的。

Function.prototype.bind = function (obj, ...args) {
  if (obj == null || obj == undefined) {
    obj = window;
  }
  const fn = function () {
    this.fn(...args);
  };
  return fn;
};

5.测试

我们来测试一下我们手写的这三者函数是否实现了。我们来创建一个对象,并通过call、apply和bind这三种方式来调用其内部的函数并打印其内部函数返回的結果。

const obj = {
  name: 'John Doe',
  age: 30,
  greet: function () {
    return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
  },
};

console.log(obj.greet.call(obj)); // Hello, my name is John Doe and I am 30 years old.
console.log(obj.greet.apply(obj)); // Hello, my name is John Doe and I am 30 years old.
console.log(obj.greet.bind(obj)); // function () {
  return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
});

const boundFunction = obj.greet.bind(obj);
console.log(boundFunction()); // Hello, my name is John Doe and I am 30 years old.

6.總結

现在我们已经实现了这三者函数,我们可以看到,这三者函数都是用来修改函数执行时的this指向的。call函数需要两个参数,第一个参数是this要指向的对象,第二个参数是参数列表。apply函数也需要两个参数,第一个参数是this要指向的对象,第二个参数是参数列表,但是参数列表必须是以数组的形式书写的。bind函数也需要两个参数,第一个参数是this要指向的对象,第二个参数是参数列表,参数列表必须是以数组的形式书写的。

这三者函数都是非常有益的,在很多场景下我们都可以使用这三者函数来修改函数执行时的this指向。