JavaScript中的new操作符:做了那些事?

引言

在 JavaScript 中,new是一个关键字,它用来创建一个新的对象实例,并执行一个构造函数。我们在实际编程中经常使用它来实例化对象。但是,new运算符背后到底做了什么呢?让我们通过分析它的内部过程,来更好地理解它的工作原理。

1.new 操作符的基本作用

new 操作符通常与构造函数一起使用,创建一个新的实例对象。比如,在我们使用构造函数 Person 来创建一个新对象时:

1
2
3
4
5
6
function Person(name, age) {
this.name = name;
this.age = age;
}

const person1 = new Person("Wyx", 27);

在这里,new Person('Wyx', 27) 实际上会返回一个新的对象实例。这个对象的构造过程不仅仅是简单地调用构造函数,它背后涉及多个步骤。

2.new 操作符的内部执行步骤

当你使用 new 操作符创建一个实例时,JavaScript 引擎会按照以下的步骤执行:

步骤 1:创建一个新对象

首先,new 操作符会创建一个空的普通对象。该对象没有任何原型链上的方法,除了基本的 Object.prototype 上的方法和属性。

1
const obj = {};

步骤 2:设置新对象的原型链

接着,新创建的对象的原型被设置为构造函数的 prototype 属性。通过这个设置,新对象就能够访问构造函数的原型方法。也就是说,这个新对象的[[Prototype]](也可以通过 __proto__ 访问)将指向构造函数的 prototype

1
obj.__proto__ = Constructor.prototype;

在上面的代码中,Constructor 就是我们使用的构造函数,比如 Person

步骤 3:将构造函数的this 指向新对象并执行构造函数

然后,new 操作符会将构造函数中的 this 指向刚刚创建的对象,并执行构造函数。这一步是关键,因为它是通过构造函数将属性和方法赋给新对象的地方。

1
Constructor.call(obj, ...args);

在这个过程中,构造函数中的所有属性都会被添加到新对象 obj 上。例如,在 Person 构造函数中,我们将 nameage属性赋给了 obj

步骤 4:返回新对象

最后,new 操作符会返回新创建的对象。如果构造函数显式地返回一个对象,那么 new 操作符会返回这个对象;如果没有返回对象,则返回第 2步中创建的对象。

1
2
const result = Constructor.apply(obj, args);
return result instanceof Object ? result : obj;

因此,new 操作符的返回结果取决于构造函数是否显式返回一个对象。如果返回了对象,new 会返回这个对象;如果没有,则默认返回创建的新对象。

3. 总结:new 的工作流程

综上所述,当你使用 new 运算符时,它会做以下几件事情:

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

4. 一个简单的示例

让我们通过一个实际示例来验证 new 运算符的工作方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Person(name, age) {
this.name = name;
this.age = age;
}

Person.prototype.sayHello = function () {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};

// 使用 new 操作符创建新实例
const person1 = new Person("Wyx", 27);

// 调用原型上的方法
person1.sayHello(); // 输出: Hello, my name is Wyx and I am 27 years old.

在这个示例中,new Person(‘Wyx’, 27) 执行了上面提到的所有步骤:

  • 它首先创建了一个新的对象 person1;
  • 然后将 person1.proto 指向 Person.prototype,这样 person1 就能访问到 sayHello 方法;
  • 接着,构造函数 Person 执行,并将 name 和 age 属性赋值给了 person1;
  • 最后,person1 被返回并赋值给变量 person1。