原型继承内存优势在于方法共享不重复分配,而构造函数式类继承易导致方法重复拷贝;es6 class默认将方法定义在prototype上,与原型继承内存行为一致;误将实例独有数据放原型会引发污染而非内存增长。

原型继承在海量实例场景下的内存优势,核心在于方法共享不重复分配,而类继承(尤其构造函数式)容易造成方法的重复拷贝。这不是理论推导,而是由 JavaScript 引擎底层对象模型决定的。
方法存储位置决定内存开销
原型继承中,所有实例共用同一份方法——它们都通过 [[Prototype]] 链指向同一个原型对象。比如:
User.prototype.sayHi = function() { console.log('Hi ' + this.name); };
const u1 = new User('Alice');
const u2 = new User('Bob');
// u1.sayHi 和 u2.sayHi 共享同一个函数引用,只存一份
而若用纯构造函数模拟“类继承”,常见写法是把方法直接挂到 this 上:
this.name = name;
this.sayHi = function() { console.log('Hi ' + this.name); }; // ❌ 每次 new 都新建函数
}
const b1 = new BadUser('Alice');
const b2 = new BadUser('Bob');
// b1.sayHi !== b2.sayHi,两个独立函数对象,各占内存
当实例数达十万级,仅一个方法就多出近 10 万份闭包或函数对象,每个至少几百字节——累积就是百 MB 级别浪费。
类语法(class)本身不等于内存浪费
ES6 class 是语法糖,其方法默认定义在 prototype 上,和规范的原型继承内存行为一致:
constructor(name) { this.name = name; }
sayHi() { console.log('Hi ' + this.name); } // ✅ 自动挂到 GoodUser.prototype
}
所以真正要对比的,不是“class vs prototype”,而是:
- ✅ 方法定义在
prototype(无论 class 或 function)→ 共享,省内存 - ❌ 方法定义在
this或闭包内 → 独立,耗内存
原型链深度影响不大,但属性冗余需警惕
有人担心“原型链太长导致查找慢”,实际现代引擎(V8、SpiderMonkey)对原型属性访问做了强缓存(IC 缓存),只要原型结构稳定,性能几乎无损。
真正易被忽略的是:把本该共享的数据误塞进原型,例如:
// ❌ 危险:所有实例共享同一个数组User.prototype.tags = [];
u1.tags.push('admin');
console.log(u2.tags); // ['admin'] —— 意外污染
这不会增加内存总量,但会引发数据错乱;正确做法是让实例自己拥有独有状态(如 this.tags = []),方法仍走原型。
结合真实规模估算更直观
假设单个用户实例含 5 个方法,每个方法对象约 400 字节:
- 10 万个实例 × 每个实例独有 5 个方法 = 100,000 × 5 × 400B ≈ 200 MB
- 同样规模,方法全在 prototype = 5 × 400B ≈ 2 KB
差三个数量级。这还没算闭包捕获上下文带来的额外对象开销。










