javascript 中通过让多个实例共享同一个原型对象来实现方法共享,具体做法是将方法定义在构造函数的 prototype 属性上。这样所有由该构造函数创建的实例都会指向同一个原型对象,从而复用内存中的方法函数。如果直接修改原型对象,所有实例都能立即访问到更新后的方法。

如何向原型添加共享方法
向原型添加共享方法只需将函数赋值给构造函数的 prototype 属性。这样做的好处是方法只存在于内存的一份副本中,所有实例都通过原型链引用它。例如,定义一个 User 构造函数,并在其原型上添加 greet 方法,任何 User 实例调用该方法时都会执行同一份代码逻辑。

function User(name) {
this.name = name;
}
User.prototype.greet = function() {
return 'Hello, I am ' + this.name;
};
const user1 = new User('Alice');
const user2 = new User('Bob');
console.log(user1.greet()); // Hello, I am Alice
console.log(user2.greet()); // Hello, I am Bob
console.log(user1.greet === user2.greet); // true
运行上述代码,user1.greet 和 user2.greet 返回相同的布尔值 true,证明它们引用的是同一个函数对象。每个实例的 this 指向各自的对象,因此输出不同的名字,但方法本身是共享的。
原型继承链中的方法查找机制
当调用实例上的方法时,JavaScript 引擎会先在实例自身属性中查找,若未找到则沿着原型链向上查找至原型对象。这种机制确保了即使实例没有自己的同名方法,也能正确执行原型上定义的共享逻辑。如果原型对象被替换为另一个对象,原有的方法引用可能会丢失,需要重新挂载或确保新原型包含所需方法。

function Animal(type) {
this.type = type;
}
Animal.prototype.speak = function() {
return this.type + ' makes a sound';
};
class Dog extends Animal {
constructor() {
super('Dog');
}
}
const dog = new Dog();
console.log(dog.speak()); // Dog makes a sound
console.log(dog.hasOwnProperty('speak')); // false
console.log(dog.speak === Animal.prototype.speak); // true
在 ES6 类继承示例中,Dog 实例 dog 自身不包含 speak 方法,hasOwnProperty 返回 false。但通过原型链查找,dog.speak 最终指向 Animal.prototype.speak,两者相等。这展示了现代语法下原型共享方法的底层行为依然一致。
直接修改原型对象对已存在实例的影响
如果在创建实例后直接修改原型对象,新增或覆盖的方法会立即对所有已存在的实例生效。这是因为实例与原型之间保持动态链接,而非静态拷贝。例如,在创建 User 实例后,向 prototype 添加新方法 farewell,之前创建的实例也能直接调用该方法,无需重新初始化。
function User(name) {
this.name = name;
}
const user1 = new User('Alice');
// 在实例创建后添加方法
User.prototype.farewell = function() {
return 'Goodbye, ' + this.name;
};
console.log(user1.farewell()); // Goodbye, Alice
const user2 = new User('Bob');
console.log(user2.farewell()); // Goodbye, Bob
上述代码显示,user1 在 farewell 方法定义前就已创建,但仍能成功调用该方法。这验证了原型对象的动态共享特性:只要原型对象被修改,所有通过该原型链访问的实例都会反映这些变化。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











