深入理解 JavaScript 的 `new`

200 阅读3分钟

在 JavaScript 中,new 关键字用于创建一个由构造函数生成的对象实例。new 的工作机制看似简单,但背后涉及了许多步骤。为了深入理解 new 关键字的原理,我们可以尝试自己实现一个类似功能的函数。在本文中,我们将逐步讲解如何实现一个自定义的 myNew 函数,并探讨其背后的工作原理。

什么是 new 关键字?

使用 new 关键字创建对象时,JavaScript 会执行以下步骤:

  1. 创建一个新的空对象。
  2. 将该对象的原型指向构造函数的 prototype 属性。
  3. 执行构造函数,并将 this 绑定到新创建的对象上。
  4. 如果构造函数返回一个对象,则返回该对象;否则,返回新创建的对象。

实现自定义的 myNew 函数

我们将按照上述步骤来实现我们的 myNew 函数。下面是完整的实现代码:

function myNew(constructor, ...args) {
    // 创建一个新的空对象,原型指向构造函数的 prototype
    let obj = Object.create(constructor.prototype);
    
    // 执行构造函数,将 this 指向新创建的对象
    let result = constructor.apply(obj, args);
    
    // 如果构造函数返回了一个对象,则返回该对象;否则,返回新创建的对象
    return result instanceof Object ? result : obj;
}

// 示例构造函数
function Example(name) {
    this.name = name;
}

// 使用 myNew 来创建实例
let obj = myNew(Example, "John");

console.log(obj.name); // 输出 "John"

代码详解

1. 创建一个新的空对象

我们使用 Object.create 创建一个新的空对象,并将其原型指向构造函数的 prototype 属性。

let obj = Object.create(constructor.prototype);

Object.create 方法创建了一个新对象,并将其原型设置为指定的对象。在这里,我们将新对象的原型设置为构造函数的 prototype 属性,以确保新对象继承构造函数的原型属性和方法。

2. 执行构造函数

接下来,我们执行构造函数,并将 this 绑定到新创建的对象上。为了实现这一点,我们使用 Function.prototype.apply 方法。

let result = constructor.apply(obj, args);

apply 方法调用一个函数,并将 this 关键字设置为提供的值,同时以数组形式传入参数。在这里,我们将 this 设置为新创建的对象,并传入构造函数的参数。

3. 返回对象

最后,我们检查构造函数的返回值。如果构造函数返回了一个对象,则返回该对象;否则,返回新创建的对象。

return result instanceof Object ? result : obj;

这是因为在 JavaScript 中,构造函数可以显式返回一个对象。如果没有显式返回对象,构造函数会默认返回新创建的对象。

示例使用

为了验证我们的 myNew 函数,我们定义一个示例构造函数 Example,并使用 myNew 创建其实例。

function Example(name) {
    this.name = name;
}

let obj = myNew(Example, "John");
console.log(obj.name); // 输出 "John"

可以看到,myNew 函数成功创建了 Example 的实例,并正确设置了 name 属性。