本文深入解析 JavaScript 中 new 运算符的执行流程,包括创建空对象、绑定 this、链接 __proto__ 及返回实例。通过构造函数示例,阐明原型链机制如何优化内存与计算资源,并展示如何在原型上添加共享方法以实现高效继承。
译者按:本文简要介绍 new 运算符,重点阐述原型(prototype)机制,推荐阅读。
原文标题:JavaScript For Beginners: the ‘new' operator
译者:Fundebug
为确保证可读性,本文采用意译方式。版权归原作者所有,翻译仅供学习使用。
new 运算符的执行流程
使用 new 关键字时,会执行以下操作:
1. 创建一个全新的空对象; 2. 将 this 关键字绑定至该对象; 3. 为该对象添加名为 __proto__ 的属性,使其指向构造函数的 prototype 属性; 4. 返回该 this 对象。
若上述概念尚不清晰,接下来将通过具体示例进行详细解析。首先定义一个名为 Student 的构造函数,该函数接收 name 和 age 两个参数。
function Student(name, age){
this.name = name;
this.age = age;
}
现在使用 new 关键字创建一个新对象:
var first = new Student('John', 26);
具体发生了什么?
1. 创建一个新的对象,暂命名为 obj; 2. 将 this 绑定至 obj,此后对 this 的任何引用均指向 obj; 3. 向 obj 对象添加 __proto__ 属性,obj.__proto__ 指向 Student.prototype; 4. 将该 obj 对象赋值给变量 first。
我们可以通过打印语句进行测试:
console.log(first.name);
// John
console.log(first.age);
// 26
接下来深入探讨 __proto__ 的相关机制。
理解原型(Prototype)
原型 (Prototype)
每个 JavaScript 对象均拥有一个原型。所有对象均从其原型中继承属性和方法。
打开浏览器开发者控制台(Windows: Ctrl + Shift + J;Mac: Cmd + Option + J),输入之前定义的 Student 函数:
function Student(name, age) {
this.name = name;
this.age = age;
}
为了验证每个对象都拥有原型,输入:
Student.prototype;
// Object {...}
你将看到一个对象被返回。现在尝试定义一个新的对象:
var second = new Student('Jeff', 50);
根据前述解释,second 指向的对象应包含 __proto__ 属性,且该属性应指向父级的 prototype,我们来验证一下:
second.__proto__ === Student.prototype
// true
Student.prototype.constructor 指向 Student 构造函数,我们打印输出查看:
Student.prototype.constructor;
// function Student(name, age) {
// this.name = name;
// this.age = age;
// }
情况似乎愈发复杂,我们通过图示进行直观描述:

Student 构造函数拥有一个名为 .prototype 的属性,该属性又包含一个 .constructor 属性反向指向 Student 构造函数,二者构成闭环。当我们使用 new 创建新对象时,每个对象的 __proto__ 属性均反向指向 Student.prototype。
原型在继承与性能优化中的作用
这种设计对继承至关重要。因为原型对象被该构造函数创建的所有对象共享。当向原型对象添加函数和属性时,所有其他对象均可访问。
本文仅创建了两个 Student 对象,若创建 20,000 个,将属性和函数置于 prototype 而非每个对象中,将极大节省存储和计算资源。
请看以下示例:
Student.prototype.sayInfo = function(){
console.log(this.name + ' is ' + this.age + ' years old');
}
我们为 Student 的原型添加了一个新函数 sayInfo,因此使用 Student 创建的所有学生对象均可访问该函数。
second.sayInfo();
// Jeff is 50 years old
创建一个新的学生对象,再次进行测试:
var third = new Student('Tracy', 15);
// 如果我们现在打印third, 虽然只会看到年龄和名字这两个属性,
// 仍然可以访问sayInfo函数。
third;
// Student {name: "Tracy", age: 15}
third.sayInfo();
// Tracy is 15 years old
在 JavaScript 中,首先检查当前对象是否拥有该属性;若无,则检查原型中是否存在。此规则持续生效,直至找到属性或到达顶层全局对象仍未找到而返回失败。
继承机制使得我们无需定义 toString() 函数即可直接使用。因为 toString() 函数内置于 Object 的原型中。我们创建的每个对象最终均指向 Object.prototype,因此可以调用 toString()。当然,我们也可以重写此函数:
var name = {
toString: function(){
console.log('Not a good idea');
}
};
name.toString();
// Not a good idea
创建的 name 对象首先检查是否拥有 toString,若拥有则不再向原型中查找。
总结
这些概念或许繁多,但理解后,利用原型可编写出更高效的代码。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。