继承
原型继承
核心思想:子类的原型成为父类的实例
实现:
function SuperType() {
this.colors = ['red', 'green'];
}
function SubType() {
}
// 原型继承关键: 子类的原型成为父类的实例
SubType.prototype = new SuperType();
// 测试
let instance1 = new SubType();
instance1.colors.push('blue');
let instance2 = new SubType();
console.log(instance2.colors); // ['red', 'green', 'blue']
原型继承存在的问题:
- 原型中包含的引用类型属性将被所有实例对象共享
- 子类在实例化时不能给父类构造函数传参
构造函数继承
核心思想:在子类构造函数中调用父类构造函数
实现:
function SuperType(name) {
this.name = name;
this.colors = ['red', 'green'];
this.getName = function() {
return this.name;
}
}
function SubType(name) {
// 继承 SuperType 并传参
SuperType.call(this, name);
}
// 测试
let instance1 = new SubType('instance1');
instance1.colors.push('blue');
console.log(instance1.colors); // ['red','green','blue']
let instance2 = new SubType('instance2');
console.log(instance2.colors); // ['red', 'green']
构造函数继承的出现是为了解决了原型继承的引用值共享问题。优点是可以在子类构造函数中向父类构造函数传参。它存在的问题是:1)由于方法必须在构造函数中定义,因此方法不能重用。2)子类也不能访问父类原型上定义的方法。
组合继承
核心思想:综合了原型链和构造函数,即,使用原型链继承原型上的方法,而通过构造函数继承实例属性。
实现:
function SuperType(name) {
this.name = name;
this.colors = ['red', 'green'];
}
Super.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
// 继承属性
SuperType.call(this, name);
// 实例属性
this.age = age;
}
// 继承方法
SubType.prototype = new SuperType();
// 测试
let instance1 = new SubType('instance1', 1);
instance1.sayName(); // "instance1"
instance1.colors.push("blue");
console.log(instance1.colors); // ['red','green','blue']
let instance2 = new SubType('instance2', 2);
instance2.sayName(); // "instance2"
console.log(instance2.colors); // ['red','green']
组合继承存在的问题是:父类构造函数始终会被调用两次:一次是在创建子类原型时new SuperType()
调用,另一次是在子类构造函数中SuperType.call()
调用。
寄生式组合继承(最佳)
核心思想:通过构造函数继承属性,但使用混合式原型继承方法,即,不通过调用父类构造函数给子类原型赋值,而是取得父类原型的一个副本。
实现:
function SuperType(name) {
this.name = name;
this.colors = ['red', 'green'];
}
Super.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
// 继承属性
SuperType.call(this, name);
this.age = age;
}
// 继承方法
SubType.prototype = Object.create(SuperType.prototype);
// 重写原型导致默认 constructor 丢失,手动将 constructor 指回 SubType
SubType.prototype.constructor = SubType;
class 实现继承(ES6)
核心思想:通过 extends
来实现类的继承(相当于 ES5
的原型继承)。通过 super
调用父类的构造方法 (相当于 ES5
的构造函数继承)。
实现:
class SuperType {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
class SubType extends SuperType {
constructor(name, age) {