返回

this call apply bind 原生实现之我见

前端

  1. this 的基本介绍

在 JavaScript 中,this 代表当前执行代码的上下文对象。this 可以是全局对象、函数对象、DOM 对象等。当函数作为对象的方法被调用时,this 指向该对象;当函数作为普通函数被调用时,this 指向全局对象。

2. call、apply 和 bind 的基本用法

call、apply 和 bind 都是 JavaScript 中的函数调用方法,它们允许函数以不同的上下文对象被调用。call 和 apply 的用法相似,都可以在指定上下文中调用函数,但两者之间存在细微的差别:

  • call 方法接受两个参数,第一个参数是需要绑定的上下文对象,第二个参数是函数的参数列表。
  • apply 方法接受三个参数,第一个参数是需要绑定的上下文对象,第二个参数是参数数组,第三个参数是函数的参数列表。

bind 方法与 call 和 apply 不同,它不立即执行函数,而是返回一个新的函数,该函数在调用时会以指定的上下文对象作为 this 来执行。

3. this、call、apply 和 bind 的原生实现

我们可以通过查看 JavaScript 引擎的源代码来了解 this、call、apply 和 bind 的原生实现。在 V8 引擎中,this、call、apply 和 bind 的实现如下:

// this
function This() {
  return this;
}

// call
Function.prototype.call = function(ctx) {
  var args = [];
  for (var i = 1; i < arguments.length; i++) {
    args.push(arguments[i]);
  }
  ctx.fn = this;
  var result = ctx.fn(...args);
  delete ctx.fn;
  return result;
};

// apply
Function.prototype.apply = function(ctx, args) {
  ctx.fn = this;
  var result = ctx.fn(...args);
  delete ctx.fn;
  return result;
};

// bind
Function.prototype.bind = function(ctx) {
  var args = [];
  for (var i = 1; i < arguments.length; i++) {
    args.push(arguments[i]);
  }
  var fn = this;
  return function() {
    var bindArgs = [];
    for (var i = 0; i < arguments.length; i++) {
      bindArgs.push(arguments[i]);
    }
    return fn.apply(ctx, args.concat(bindArgs));
  };
};

从上面的代码中,我们可以看到 this、call、apply 和 bind 的原生实现都是通过修改函数的 this 指针来实现的。

4. 箭头函数在作为构造函数时的问题

箭头函数没有自己的 this,因此不能作为构造函数。当箭头函数作为构造函数被调用时,this 会指向全局对象。这可能会导致一些问题,例如:

  • 无法使用 this 来访问对象的方法和属性。
  • 无法使用 new 操作符来创建对象的实例。

为了解决这个问题,我们可以使用 call、apply 或 bind 方法来显式地将 this 指向正确的上下文对象。

5. 总结

this、call、apply 和 bind 是 JavaScript 中非常重要的函数调用方法,它们可以使函数以不同的上下文对象被调用。通过理解 this、call、apply 和 bind 的工作原理及其原生实现,我们可以更好地理解 JavaScript 中函数的执行机制。