继承的实现方式之 组合继承

基本形式

通过原型链继承原型属性及方法,通过假借构造函数继承实例属性及方法。

function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue"];
}
SuperType.prototype.sayName = function(){
    console.log(this.name);
}

function SubType(name, age){
    SuperType.call(this, name);
    this.age = age;
}

SubType.prototype = new SuperType();

SubType.prototype.sayAge = function(){
    console.log(this.age);
}


let instance1 = new SubType("Jack", 19);
instance1.colors.push("black");
console.log(instance1.colors);//["red", "blue", "black"]
instance1.sayName();//Jack
instance1.sayAge();//19

let instance2 = new SubType("Ann", 29);
instance2.colors.push("pink");
console.log(instance2.colors);//["red", "blue", "pink"]
instance2.sayName();//Ann
instance2.sayAge();//29

delete instance1.colors;
delete instance2.name;
console.log(instance1.colors); 
// ["red", "blue"] 是原型SuperType实例上的colors
console.log(Object.getOwnPropertyNames(instance1));//["name", "age"]

 

优点:结合了原型链继承和假借构造函数继承的优点

  1. 可以继承父类的原型属性及方法
  2. 可以形成原型链,使得子类实例和父类原型间iinstanceof和isPropertyOf判断为真
  3. 实例之间不用共享属性
  4. 可以向父类构造函数传参

缺点

SuperType构造函数被调用了两次,第一次调用在改变子类原型时,把一个父类实例设为了子类原型;第二次调用在通过new调用子类构造函数时,假借了父类的构造函数继承父类的实例属性。

但在第一次调用以后,父类的实例属性和方法实际成为了子类的原型属性和方法,只是在创建对象假借构造函数时,这些原型方法被同名的实例方法隐藏了,实际访问不到。因此,始终有一套访问不到的属性在子类的原型上,造成了空间的浪费。并且如果我们想删除子类实例上的同名属性,会发现删除以后该属性仍然能够访问到,因为原型上的属性仍然存在。

posted @ 2020-07-15 07:02  studystudyxinxin  阅读(160)  评论(0编辑  收藏  举报