原型链继承
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 获取父类原型的副本。
// oldDog.prototype = new Animal();Dog.prototype.constructor = Dog;// newfunction 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;}}
