JavaScript中new实例化分四步:先在堆中创建空对象,再将其__proto__指向构造函数原型,接着执行构造函数填充自有属性,最后返回堆中对象引用。
JavaScript 中 new 在实例化过程中,内存分配不是“一次性拍板”,而是分阶段、有策略地在堆内存中完成的。它不直接分配完整对象,而是先预留空间、再逐步填充,并通过原型链共享方法,避免重复开销。
执行 new Person("Alice") 时,第一步是向堆内存申请一块新空间,生成一个**空对象**(如 {})。这个对象本身不含任何自有属性,但已具备基本对象结构,包括隐式原型 __proto__ —— 此刻它默认指向 Object.prototype,尚未与构造函数关联。
第二步将该空对象的 __proto__ 指针重定向到 Person.prototype。这一步只是修改引用地址,不分配新内存:
- __proto__ 是个指针,指向已存在的原型对象(通常在堆中早于实例就存在)
- 原型对象里的方法(如 Person.prototype.sayName)被所有实例共享,不随每个实例重复复制
- 实例自身只存储“独有数据”,比如 name、age 等自有属性
第三步调用 Person.call(新对象, "Alice"),此时 this 指向刚分配的堆内存地址,构造函数内部对 this.name = "Alice" 的赋值,就是往那块堆空间里写入字段:
"Alice" 存在堆中(或字符串常量池),name 属性保存的是对该字符串的引用this.getName = function(){...}),该函数也会被创建在堆中,且每个实例都拥有一份 —— 这是常见内存浪费点prototype 上,让实例通过原型链访问,节省堆空间第四步判断构造函数返回值:
- 若返回的是对象(含 null),则直接返回该对象(可能覆盖原实例)
- 否则,返回最初分配的那个堆内存对象
无论哪种情况,最终变量持有的都是一个**堆内存地址引用**,栈中只存这个地址,而非整个对象数据。