原型链继承
function Animal() {
this.colors = ['yellow','red'];
}
Animal.prototype.getColor = function () {
return this.colors;
};
function Dog() {}
Dog.prototype = new Animal();
let dog1 = new Dog();
dog1.colors.push('green');
let dog2 = new Dog();
console.log(dog2.colors); // ['yellow','red', 'green']
原型链继承存在的问题:
- 原型中包含的引用类型属性将被所有实例共享
- 子类的实例化的时候不能给父类构造函数传参
借用构造函数实现继承
function Animal(name) {
this.name = name;
this.colors = ['yellow','red'];
this.getName = function () {
return this.name;
}
}
function Dog(name) {
Animal.call(this, name);
}
Dog.prototype = new Animal();
let dog1 = new Dog('dog1');
dog1.colors.push('green');
let dog2 = new Dog('dog2');
console.log(dog2.colors); // ['yellow','red']
借用构造函数实现继承解决了原型链继承的2个问题:引用类型共享问题以及传参问题。但是由于方法必须定义在构造函数中,所以会导致每次创建子类实例都会创建一遍方法。
组合继承
组合继承结合了原型链和借用构造函数,将两者的优点集中了起来。基本的思路是使用原型链继承原型上的属性和方法,而通过借用构造函数继承实例属性。这样既可以把方法定义在原型上以实现重用,又可以让每个实例都有自己的属性。
function Animal(name) {
this.name = name;
this.colors = ['yellow','red'];
}
Animal.prototype.getName = function(){
return this.name;
};
function Dog(name,age) {
Animal.call(this, name);
this.age = age;
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
let dog1 = new Dog('dog1',11);
dog1.colors.push('green');
let dog2 = new Dog('dog2',22);
console.log(dog2);
寄生式组合继承
组合继承已经相对完善了,但是还存在问题,它的问题就是调养了 2 次父类构造函数,第一次是在 new Animal(),第二次是在 Animal.call();
所以解决方案就是不直接调用父类构造函数给子类原型复制,而是通过创建空函数 F 获取父类原型的副本。
// old
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
// new
function F() {}
F.prototype = Animal.prototype;
let f = new F();
f.constructor = Dog;
Dog.prototype = f;
class 实现继承
class Animal {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
class Dog extends Animal{
constructor(name,age){
super(name);
this.age = age;
}
}