很多开发者刚接触 JavaScript 时,总觉得 new 关键字像个黑盒 —— 输入一个构造函数,出来一个对象,中间发生了什么?其实 JavaScript new 关键字内部执行流程 非常清晰,一共就四步,每一步都有明确的职责。本文就把它拆开细看,帮助理解 new 实例化过程 的内存分配与原型链机
JavaScript new绑定实例化时的内存分配
时间:2026-07-06
浏览:341
文章目录
很多开发者刚接触 JavaScript 时,总觉得 new 关键字像个黑盒 —— 输入一个构造函数,出来一个对象,中间发生了什么?其实 JavaScript new 关键字内部执行流程 非常清晰,一共就四步,每一步都有明确的职责。本文就把它拆开细看,帮助理解 new 实例化过程 的内存分配与原型链机制。

在 JavaScript 中,new 操作符 在执行构造函数时,内存分配并非“一次性拍板”,而是分阶段、有策略地在堆内存中完成的。它不会直接分配一个完整对象,而是先预留空间,再逐步填充,并通过原型链共享方法,从而避免重复开销。下面按步骤展开说明 new 底层原理。
堆内存中创建空对象
当你执行 new Person("Alice") 时,第一步是向堆内存申请一块新空间,生成一个空对象({})。这个对象本身不含任何自有属性,但它已经具备了基本对象结构,包括隐式原型 __proto__ —— 注意,此刻 __proto__ 默认指向 Object.prototype,尚未与构造函数关联。也就是说,第一步只是“搭了个空架子”,后面的步骤才往里填内容。这是 JavaScript 实例化过程 中内存分配的起始点。
原型链接改写,不额外占用内存
第二步把刚刚那个空对象的 __proto__ 指针重定向到 Person.prototype。这一步仅仅是修改引用地址,不分配新内存。如何理解?
__proto__本质上是个指针,指向已存在的原型对象(这个原型对象通常在堆中早于实例就存在,由构造函数定义时生成)- 原型对象里的方法(如
Person.prototype.sayName)被所有实例共享,不会随每个实例重复复制 - 实例自身只存储“独有数据”,比如
name、age等自有属性
因此这一步几乎不占额外内存,只是把已有的原型链接挂上。在 new 绑定 过程中,这正是实现方法复用的关键。
构造函数执行时填充实例数据
第三步调用 Person.call(新对象, "Alice"),此时 this 指向刚分配的堆内存地址。构造函数内部对 this.name = "Alice" 的赋值,就是往那块堆空间里写入字段:
- 字符串
"Alice"存在堆中(或字符串常量池),name属性保存的是对该字符串的引用 - 如果构造函数内定义了函数(如
this.getName = function(){...}),这个函数也会被创建在堆中,而且每个实例都拥有一份 —— 这是常见的内存浪费点 - 推荐把方法挂到
prototype上,让实例通过原型链访问,这样只存一份,节省堆空间
这一步清晰展示了:实例负责保存自己的专属数据,共享行为则交给原型。这也是 JavaScript 内存分配 策略的典型体现。
返回对象始终指向堆中实体
第四步判断构造函数的返回值:
- 若返回的是对象(包含
null),则直接返回该对象(可能会覆盖原本创建的实例) - 否则,返回最初分配的那个堆内存对象
无论哪种情况,最终变量持有的都是一个堆内存地址引用,栈中只存这个地址,而不是整个对象数据。所以当你执行 let p = new Person("Alice") 时,p 变量里存的就是那个堆地址,对象本身始终待在堆中。理解 new 关键字执行步骤,就能清楚掌握 JavaScript 中实例化与原型链的底层机制。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。