在浏览器兼容场景下,理解 javascript 继承机制的核心在于区分 es5 的原型链实现与 es6 的 class 语法糖。现代浏览器通过 extends 关键字提供标准的类继承,而旧版浏览器(如 ie11)仅支持基于原型的寄生组合式继承。开发者应优先使用 babel 等工具将 es6 代码转译为 es5 原型链模式,以确保在所有环境中行为一致。

ES6 Class 继承的标准行为是什么
ES6 的 class 语法提供了直观的继承结构,子类通过 extends 关键字继承父类,并在构造函数中必须调用 super() 来初始化父类状态。这种机制在底层依然依赖原型链,但封装了复杂的属性查找逻辑,使得实例创建和静态方法继承更加规范。

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');
dog.speak(); // Rex barks.
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
上述代码展示了标准的继承流程。Dog 继承了 Animal 的方法,并通过 super() 调用了父类构造函数。运行结果显示 dog 既是 Dog 的实例,也是 Animal 的实例,验证了原型链的正确连接。
立即学习“Java免费学习笔记(深入)”;
ES5 环境下如何实现兼容继承
在不支持 class 的浏览器中,需手动实现寄生组合式继承。这种方法通过设置子类的原型为父类实例的副本,并修正构造函数指向,从而避免父类构造函数被重复调用,同时保持原型链的整洁。

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;
var dog = new Dog('Rex', 'German Shepherd');
dog.speak(); // Rex makes a noise. (注意:此处未重写speak)
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
该实现中,Animal.call(this, name) 确保了每个实例拥有独立的 name 属性,而 Object.create 建立了正确的原型链接。这种方式在 IE9+ 环境中完全可用,是处理兼容性问题的标准方案。
子类重写父类方法时的执行顺序如何确定
当子类重写父类方法时,JavaScript 引擎会沿着原型链向上查找。如果子类定义了同名方法,则直接执行子类版本;若需调用父类逻辑,必须在子类方法中显式引用父类原型上的方法。这种机制确保了多态性的正确实现,同时允许开发者灵活扩展或修改行为。
// 基于 ES6 示例的修改
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
speak() {
// 显式调用父类方法
super.speak();
console.log(this.name + ' barks.');
}
}
const dog = new Dog('Rex', 'German Shepherd');
dog.speak();
// Rex makes a noise.
// Rex barks.
在此场景中,super.speak() 明确调用了 Animal.prototype.speak。执行顺序为先输出父类消息,再输出子类特有消息。这种显式调用避免了隐式原型查找的不确定性,使代码意图更清晰。


















