将方法挂到构造函数prototype上可让所有实例共享同一份函数代码,避免重复创建;应统一挂载而非在构造函数内定义,且不可在prototype上放置可变引用类型。

把方法挂到构造函数的 prototype 上,是让所有实例共用同一份函数代码、避免重复创建的最直接方式。关键不在“能不能放”,而在于“怎么放才安全、可维护、不踩坑”。
统一挂载到 prototype,别写在构造函数里
每次 new 都会执行构造函数。如果在里面用 this.say = function() {...},每个实例都会生成一个新函数对象——100 个实例就是 100 份相同逻辑的函数,纯属内存浪费。
- ✅ 正确做法:在构造函数外部,通过
Person.prototype.say = function() { console.log(this.name); }添加 - ✅ 批量定义也行,但必须手动补上
constructor: Person,否则实例的.constructor会指向Object,影响instanceof和类型判断 - ❌ 不要覆盖整个
prototype却漏掉constructor,也不要反复赋值导致原型链断裂
区分“可共享”和“不可共享”的内容
原型适合放**函数方法**和**不可变的默认值**(比如 Person.prototype.species = 'Homo sapiens'),但绝不该放可变的引用类型。
- ✅ 方法、只读配置、常量数据 → 安全挂原型
- ❌ 数组、对象、日期等引用类型 → 挂了就所有实例共用一份,一人改,全员同步变(比如
Person.prototype.hobbies = []是典型错误) - ⚠️ 实例自有属性(如
this.name)始终优先于原型成员,不会被覆盖,也不干扰共享逻辑
验证是否真正共享
光写对不行,得确认函数确实是同一份。最简单的方法是比引用:
const a = new Person('Alice');const b = new Person('Bob');a.say === b.say // true → 表明共用同一个函数对象- 如果返回
false,说明方法没挂对位置,或者被实例自身属性遮蔽了
现代写法更省心,但原理不变
ES6 的 class 语法不是新机制,只是封装了原型操作:
class Person { constructor(name) { this.name = name; } say() { console.log(this.name); } }- 编译或运行时,
say依然落在Person.prototype上,自动处理constructor,不易出错 - 它没改变原型链本质,只是让共享更直观、更难写错











