前言
本篇文章主要理解 new 操作符的原理,并手写实现一个自己的 "new"
new 操作符在背后做了什么?
在上篇文章中讲解了原型与原型链,讲到了使用 new 操作符创建实例对象
- 为什么 new 操作符创建的对象会拥有构造函数上的全部属性和方法?
- 为什么实例对象上的原型指针会指向构造函数的原型?
要明白这些问题,就要知道 new 操作符在实例化时做了什么
翻开《JavaScript 高级程序设计》第四版中关于原型的篇章,当以 new 关键字调用函数时,会执行以下操作:
- 在内存中创建一个新对象
- 这个新对象内部的
[[Prototype]]
特性被赋值为构造函数的 prototyoe 属性 - 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)
- 执行构造函数内部的代码(给新对象添加属性)
- 如果构造函数返回非空对象,返回这个对象;否则,返回新创建的对象
手写自己的 new 操作符
按照上面流程,我们可以模拟写一个自己的 new
比如,我们拥有一个 myNew
函数
js
function myNew(constructor, ...args) {
// 1.在内存中创建一个新对象
// 2.这个新对象内部的 `[[Prototype]]` 特性被赋值为构造函数的 prototyoe 属性
const obj = Object.create(constructor.prototype);
// 3. 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)
// 4. 执行构造函数内部的代码(给新对象添加属性)
const result = constructor.apply(obj, args);
// 5. 如果构造函数返回非空对象,返回这个对象;否则,返回新创建的对象
return (result !== null && typeof result === 'object') ? result : obj;
}
解析:
使用 Object.create
来实现第一步、第二步,这个方法会创建一个新对象,并且将新对象的原型指针指向传入的对象的原型

在第三步和第四步,使用了函数上的实例方法 Function.protytype.apply
这个方法会改变函数内部的 this
指向,并且将剩余的参数(arguments
)作为数组传入,然后调用该函数
手写的效果
在谷歌浏览器 - F12 开发者工具上测试效果

总结
实例对象拥有构造函数的全部属性和方法,并且原型指针指向构造函数的原型,都是 new 操作符在背后做的工作:
- 在内存中创建一个新对象
- 这个新对象内部的
[[Prototype]]
特性被赋值为构造函数的 prototyoe 属性 - 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)
- 执行构造函数内部的代码(给新对象添加属性)
- 如果构造函数返回非空对象,返回这个对象;否则,返回新创建的对象
记住,手写实现 new 操作符,本质是为了实践理解 new 操作符的背后原理
参考资料
- MDN - Object.create
- MDN - new
- 《JavaScript 高级程序设计》第四版
参透JavaScript系列
本文已收录至《参透 JavaScript 系列》,全文地址:我的 GitHub 博客 | 掘金专栏
交流讨论
对文章内容有任何疑问、建议,或发现有错误,欢迎交流和指正