现有两个构造函数,如下:
function Animal(){
this.special="动物";
}
function Cat(name,color){
this.name=name;
this.color=color;
}
想在我们想要让Cat构造函数继承Animal构造函数中的属性,有如下方法:
1.在子类构造函数中直接通过call/apply的方式直接引入父类构造函数,如下:
function Cat(name,color){
Animal.call(this,arguments);
this.name=name;
this.color=color;
}
var cat=new Cat("喵喵","yellow");
console.log(cat.special);
2.使用prototype属性:
Cat.prototype=new Animal();//Cat的原型指向Animal的实例
Cat.prototype.constructor=Cat;
var cat1=new Cat("miaomiao","yellow");
console.log(cat1.special);
解释:
第一行:我们把Cat的原型指向了Animal的实例
Cat.prototype=new Animal();
第二行:
Cat.prototype.constructor=Cat;
每一个构造函数的原型上面都有一个constructor的属性,这个属性指向它自己的构造函数,即我们在不错任何操作的情况下,查看Cat.prototype.constructor,会给我们输出Cat构造函数,如下图:
2020-08-08_221855.png
但现在我们使用prototype属性实现继承的时候,把Cat.prototype指向了Animal的实例,那么Cat.prototype.constructor的指向就发生了变化,如下图:
222.png
有人会疑惑,指向Animal就指向Animal呗!为什么又要重新指向回来呢???
原因如下:档我们把Cat实例之后,即cat1,每一个实例同样都有一个constructor属性,默认调用的是prototype的constructor属性,即cat1实例的constructor属性应该调用的是Cat.prototypr.constructor,即:
cat1.constructor==Cat.prototype.constructor //true
333.png
所以第二行我们要把 Cat.prototype.constructor重新指向Cat;
3.直接继承prototype
第三种方法是对第二种方法的改进。由于Animal对象中,不变的属性都可以直接写入Animal.prototype。所以,我们也可以让Cat()跳过 Animal(),直接继承Animal.prototype。
第三种方法我们把父类构造函数的属性放在父类的原型上,即:
function Animal(){}
Animal.prototype.special="动物";
function Cat(name,color){
this.name=name;
this.color=color;
}
Cat.prototype=Animal.prototype;
Cat.prototype.constrctor=Cat;
var cat1=new Cat("miaomiao","yellow");
console.log(cat1.special);
与前一种方法相比,这样做的优点是效率比较高(不用执行和建立Animal的实例了),比较省内存。缺点是 Cat.prototype和Animal.prototype现在指向了同一个对象,那么任何对Cat.prototype的修改,都会反映到Animal.prototype。
5.拷贝继承:
function Animal(){}
Animal.prototype.special="动物";
function Cat(name,color){
this.name=name;
this.color=color;
}
function extend(parent,child){
var p=parent.prototype;
var c=child.prototype;
for(var i in p){
c[i]=p[i];
}
c.uber=p;
}
extend(Animal,Cat);
var cat1=new Cat("miaomiao","yellow");
console.log(cat1.special);