JavaScript各种继承方式(三):组合继承(combination inheritance)
一 原理
组合继承仅仅是同时使用了原型链继承和构造函数继承。
具体做法是,将父类的实例作为子类的构造函数的原型对象,并在子类的构造函数中调用父类的构造函数。
function Fruit(name){ this.name = name; this.nutrition = ['维生素']; } Fruit.prototype.eat = function(){ console.log('eat'); } function Mango(name,level){ Fruit.call(this,name); // 第二次调用父类的构造函数 this.level = level; } let fruit = new Fruit(); // 第一次调用父类的构造函数 Mango.prototype = fruit; Mango.prototype.constructor = Mango; let mango1 = new Mango('泰国芒果','优'); let mango2 = new Mango('海南芒果','良'); // 子类的实例持有两份继承的属性:一份是共享原型对象中的属性;另一份是自己的私有属性。 mango1.nutrition.push('膳食纤维'); mango2.nutrition.push('柠檬酸'); console.log(mango1.nutrition,mango1.__proto__.nutrition); // ["维生素", "膳食纤维"] ["维生素"] console.log(mango2.nutrition,mango2.__proto__.nutrition); // ["维生素", "柠檬酸"] ["维生素"] console.log(mango1.__proto__.nutrition === mango2.__proto__.nutrition); // true // 拼接了原型链,支持instanceof、isPrototypeOf console.log(mango1 instanceof Fruit); // true console.log(mango1 instanceof Mango); // true console.log(Fruit.prototype.isPrototypeOf(mango1)); // true console.log(fruit.isPrototypeOf(mango1)); // true
二 优点
1 既可以从父类的构造函数的原型对象继承方法,也能从父类的构造函数继承属性。
2 既是父类的实例,也是子类的实例。
3 拼接了原型链,支持instanceof、isPrototypeOf检测。
4 调用父类的构造函数时可以传参数。
5 从父类的构造函数的原型对象继承的方法,可以被复用,被所有子类的实例共享。
三 缺点
父类的构造函数执行了两次,从而父类的实例属性被创建了两次,在子类的原型对象、子类的实例中都存在。父类的实例属性被继承了两次,子类的实例中的属性覆盖了子类的原型对象中的属性。浪费了内存和性能。