javascript通过原型对象实现方法的动态共享,即多个实例共用prototype上的同一函数,节省内存且支持运行时修改;需避免直接覆盖prototype而应逐个添加或用object.assign。

JavaScript 中通过原型对象实现行为的动态共享,核心在于让多个实例对象共用同一个方法(函数)定义,而不是每个实例都单独保存一份副本。这样既节省内存,又支持运行时修改——改原型上的方法,所有已存在和未来创建的实例都会立即“看到”变化。
把方法挂到构造函数的 prototype 上
这是最基础也最关键的一步。只要把函数赋值给构造函数的 prototype 属性,所有通过该构造函数创建的实例,就能通过原型链访问它:
function Person(name) {
this.name = name;
}
// 把方法定义在原型上,而非构造函数内部
Person.prototype.sayHello = function() {
console.log('Hello, I am ' + this.name);
};
const a = new Person('Alice');
const b = new Person('Bob');
a.sayHello(); // Hello, I am Alice
b.sayHello(); // Hello, I am Bob
此时 a 和 b 都没有自己的 sayHello 方法,但调用时会沿着原型链找到 Person.prototype.sayHello,实现共享。
运行时修改原型,所有实例即时生效
原型对象是真实存在的普通对象,可以随时增、删、改。这种修改会立刻反映在所有已创建的实例上,体现“动态共享”:
// 动态重写方法
Person.prototype.sayHello = function() {
console.log('Hi there! ' + this.name.toUpperCase());
};
a.sayHello(); // Hi there! ALICE
b.sayHello(); // Hi there! BOB
// 甚至可以新增方法,老实例也能用
Person.prototype.getNameLength = function() {
return this.name.length;
};
console.log(a.getNameLength()); // 5
注意:避免直接覆盖整个 prototype
如果直接给 prototype 赋一个新对象(比如 Person.prototype = { ... }),会切断已有实例的原型链连接,导致它们无法访问新方法:
const c = new Person('Charlie');
Person.prototype = { sayBye: function() { console.log('Bye!'); } };
c.sayBye(); // ❌ TypeError: c.sayBye is not a function
正确做法是逐个添加属性,或使用 Object.assign() 合并到现有 prototype:
- ✅ 推荐:用 Person.prototype.newMethod = function(){}
- ✅ 或:Object.assign(Person.prototype, { method1(){}, method2(){} })
- ❌ 避免:Person.prototype = { ... }(除非你明确知道后果且重置了 constructor)
ES6 class 本质仍是原型机制
class 写法只是语法糖,底层依然操作 prototype:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a sound');
}
}
// 等价于:Animal.prototype.speak = function() { ... }
所以 class 中定义的实例方法,天然就是共享在原型上的,也支持动态修改 —— 改 Animal.prototype.speak,所有 Animal 实例的行为就变了。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











