返回

手撕新、调用、应用、绑定,然后重新实现一遍

前端

揭开 JavaScript 函数调用魔术的面纱:深入了解 new、call、apply 和 bind

在 JavaScript 的广阔世界中,new、call、applybind 这四个函数充当了强大的工具,让你可以灵活地调用函数,从而增强代码的可复用性和可扩展性。

new:创建对象的起点

new 运算符是创建新对象的桥梁。它调用构造函数,为新对象分配内存,并设置其内部属性。构造函数的作用就像一个蓝图,定义对象的属性和行为。

call 和 apply:改变函数的上下文

callapply 允许你改变函数调用的上下文。它们让你可以使用不同的对象作为函数的 this ,就像把函数“借”给其他对象使用一样。

bind:创建预先绑定的函数

bind 不同于 call 和 apply,它并不立即调用函数,而是创建一个新的函数,该函数被绑定到特定的上下文。这个新函数在以后调用时,无论你使用什么对象调用,它都会保持绑定的上下文。

重新实现这些函数:深入了解它们的内部机制

要真正理解这些函数,我们不妨尝试自己重新实现它们:

new

function new(constructor, ...args) {
  const obj = {};
  Object.setPrototypeOf(obj, constructor.prototype);
  const result = constructor.apply(obj, args);
  return typeof result === 'object' ? result : obj;
}

call

Function.prototype.call = function(context, ...args) {
  context = context || globalThis;
  context.fn = this;
  const result = context.fn(...args);
  delete context.fn;
  return result;
};

apply

Function.prototype.apply = function(context, args) {
  context = context || globalThis;
  context.fn = this;
  const result = context.fn(...args);
  delete context.fn;
  return result;
};

bind

Function.prototype.bind = function(context, ...args) {
  const fn = this;
  return function(...newArgs) {
    return fn.apply(context, [...args, ...newArgs]);
  };
};

常见问题解答

  1. 为什么使用 call 和 apply 而不用 bind?

    • call 和 apply 允许你立即调用函数,而 bind 则创建了一个预先绑定的函数,可以在以后调用。
  2. new、call、apply 和 bind 之间有什么区别?

    • new 创建对象,call 和 apply 改变函数的上下文,bind 创建预先绑定的函数。
  3. 如何使用 bind 来创建类实例?

    • 通过将类构造函数作为 bind 的第一个参数,并传递所需的属性作为额外参数,可以创建类的实例。
  4. call、apply 和 bind 如何处理箭头函数?

    • 箭头函数没有自己的 this 关键字,因此 call、apply 和 bind 对它们无效。
  5. 这些函数在现代 JavaScript 中的使用情况是什么?

    • 它们仍然在 JavaScript 中广泛使用,特别是在处理复杂的对象和函数调用时。

结论

掌握 new、call、applybind 等函数,可以极大地增强你的 JavaScript 编程能力。它们提供了一种灵活的方法来调用函数,从而提高代码的可复用性和可维护性。了解这些函数的底层原理,将为你打开创造更强大、更优雅的 JavaScript 程序的大门。