js实现继承原理
JavaScript 继承实现原理
JavaScript 的继承主要通过原型链(Prototype Chain)实现,结合构造函数和原型对象的特性来完成继承关系。以下是几种常见的继承实现方式及其原理。
原型链继承
原型链继承是通过让子类的原型对象指向父类的实例来实现继承。子类实例可以通过原型链访问父类的属性和方法。
function Parent() {
this.name = 'Parent';
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child() {}
Child.prototype = new Parent(); // 子类原型指向父类实例
const child = new Child();
child.sayName(); // 输出 'Parent'
缺点:父类的引用类型属性会被所有子类实例共享,修改一个实例的属性会影响其他实例。
构造函数继承
构造函数继承通过在子类构造函数中调用父类构造函数(使用 call 或 apply)实现继承。这种方式可以避免引用类型属性共享的问题。
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
function Child(name) {
Parent.call(this, name); // 在子类中调用父类构造函数
}
const child1 = new Child('Child1');
child1.colors.push('green');
console.log(child1.colors); // ['red', 'blue', 'green']
const child2 = new Child('Child2');
console.log(child2.colors); // ['red', 'blue']
缺点:父类原型上的方法无法被子类继承。
组合继承
组合继承结合了原型链继承和构造函数继承的优点,既能继承父类的属性,又能继承父类原型上的方法。
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child(name, age) {
Parent.call(this, name); // 继承属性
this.age = age;
}
Child.prototype = new Parent(); // 继承方法
Child.prototype.constructor = Child; // 修复构造函数指向
const child = new Child('Child', 10);
child.sayName(); // 输出 'Child'
console.log(child.colors); // ['red', 'blue']
缺点:父类构造函数被调用了两次(Parent.call 和 new Parent()),效率较低。
原型式继承
原型式继承通过一个临时构造函数实现对象的浅拷贝,类似于 Object.create 的实现方式。
function createObject(obj) {
function F() {}
F.prototype = obj;
return new F();
}
const parent = {
name: 'Parent',
colors: ['red', 'blue']
};
const child = createObject(parent);
console.log(child.name); // 'Parent'
缺点:引用类型属性会被所有实例共享。
寄生式继承
寄生式继承在原型式继承的基础上增强对象,添加额外的方法或属性。
function createEnhancedObject(obj) {
const clone = Object.create(obj);
clone.sayName = function() {
console.log(this.name);
};
return clone;
}
const parent = { name: 'Parent' };
const child = createEnhancedObject(parent);
child.sayName(); // 输出 'Parent'
缺点:方法无法复用,每个实例都会创建新的方法。
寄生组合式继承
寄生组合式继承是目前最理想的继承方式,通过减少父类构造函数的调用次数来提高效率。
function inheritPrototype(child, parent) {
const prototype = Object.create(parent.prototype); // 创建父类原型的副本
prototype.constructor = child; // 修复构造函数指向
child.prototype = prototype; // 赋值给子类原型
}
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child(name, age) {
Parent.call(this, name); // 继承属性
this.age = age;
}
inheritPrototype(Child, Parent); // 继承方法
const child = new Child('Child', 10);
child.sayName(); // 输出 'Child'
优点:只调用一次父类构造函数,避免不必要的属性重复创建,同时保持原型链的完整性。
ES6 的 class 继承
ES6 引入了 class 和 extends 语法,简化了继承的实现,底层仍然是基于原型链的机制。
class Parent {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
class Child extends Parent {
constructor(name, age) {
super(name); // 调用父类构造函数
this.age = age;
}
}
const child = new Child('Child', 10);
child.sayName(); // 输出 'Child'
特点:语法简洁,易于理解,推荐在支持 ES6 的环境中使用。







