javascript 的继承机制通过原型链(prototype chain)实现内存管理,核心在于利用对象间的引用关系共享属性和方法,从而避免在子类实例中重复存储相同的函数代码。具体做法是让子类的原型对象指向父类的实例或构造函数,这样子类实例在访问属性时,会沿着原型链向上查找,未找到的属性由父级提供,实现了内存的高效复用。

构造函数与原型链如何建立关联
构造函数负责为每个新创建的实例分配独立的内存空间来存储实例特有的属性,而原型对象则作为共享区域存放所有实例共用的方法。这种分离设计确保了即使创建成千上万个实例,方法代码只会在内存中存在一份副本。当调用 new 关键字时,引擎会自动创建一个新对象,将其内部原型链接到构造函数的 prototype 属性上,并执行构造函数体内的代码初始化实例属性。

function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a noise');
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() {
console.log(this.name + ' barks');
};
const dog = new Dog('Rex', 'German Shepherd');
console.log(dog.name); // Rex
console.log(dog.breed); // German Shepherd
dog.speak(); // Rex barks
上述代码展示了经典的寄生组合式继承模式。首先定义 Animal 构造函数及其原型方法 speak。接着定义 Dog 构造函数,使用 Animal.call(this, name) 在 Dog 的上下文中执行 Animal 的代码,从而将 name 属性绑定到当前实例。关键步骤是 Dog.prototype = Object.create(Animal.prototype),这创建了一个新的空对象,其原型指向 Animal.prototype,从而建立了正确的原型链连接,同时避免了直接赋值导致的 constructor 属性丢失问题。最后修正 constructor 并添加 Dog 特有的 speak 方法。运行结果验证了实例拥有自己的属性,且能正确调用重写后的方法。
ES6 Class 语法下的内存布局有何不同
ES6 的 class 语法是构造函数的语法糖,其底层的内存管理机制与原型链完全一致。使用 extends 关键字时,JavaScript 引擎依然会在后台设置原型链,确保子类实例能够访问父类的方法。区别在于 class 提供了更清晰的声明结构,并且强制要求在使用 super() 之前不能访问 this,这在语义上更严格地约束了继承过程中的初始化顺序,但最终的内存分布依然是父类方法存储在 Parent.prototype 中,子类实例通过 [[Prototype]] 指针进行查找。

class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise');
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
speak() {
console.log(this.name + ' barks');
}
}
const dog = new Dog('Rex', 'German Shepherd');
console.log(dog.name); // Rex
console.log(dog.breed); // German Shepherd
dog.speak(); // Rex barks
这段 ES6 代码实现了与前例相同的功能。在内存中,dog 实例拥有一个指向 Dog.prototype 的内部链接,而 Dog.prototype 又有一个指向 Animal.prototype 的内部链接。speak 方法在 Dog.prototype 中被覆盖,因此调用 dog.speak() 时会直接找到子类版本。如果调用一个未在 Dog 中定义的方法,例如假设有一个 sleep 方法只在 Animal 中定义,引擎会沿着原型链找到 Animal.prototype.sleep 并执行。这种机制保证了内存的高效性,因为无论创建多少个 Dog 实例,Animal 和 Dog 的原型方法都只占用一份内存空间。
原型链断裂会导致什么具体问题
如果在继承过程中错误地修改了子类的原型对象,例如直接使用字面量赋值 Dog.prototype = { ... } 而不是 Object.create(Animal.prototype),就会切断原型链。这会导致子类实例无法访问父类原型上的任何方法,尽管父类的实例属性可能通过 call 或 apply 成功绑定。此外,这种操作还会导致 constructor 属性指向错误,使得通过 instanceof 检查时返回错误的结果,影响类型判断逻辑的正确性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











