1.原型链继承
function Parent () {this.name = 'aa';}
Parent.prototype.getName = function () {
console.log(this.name);
}
function Child () {}
Child.prototype = new Parent();
var child = new Child();
console.log(child.getName()) // aa
特点:
- 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
- 父类新增原型方法/原型属性,子类都能访问到
- 简单,易于实现
缺点:
- 要想为子类新增属性和方法,必须要在new Child()这样的语句之后执行,不能放到构造器中
- 无法实现多继承
来自原型对象的引用属性被所有实例共享
创建子类实例时,无法向父类构造函数传参
2.构造函数继承
function a2() {this.color=[1,2,3,4]; }
function b2() {a2.call(this); }
var instance2=new b2();
instance2.color.push(5);
console.log(instance2.color);//[1, 2, 3, 4, 5]
var instance3=new b2();
console.log(instance3.color);//[1, 2, 3, 4]
//上面两个例子主要想指出,instance2对构造函数的数组做修改是不会影响到其他的实例,
//因为它改的是属于它自己的那一份,不像原型那样大家共享
//------------------------//
function a3(name) { this.name=name; }
function b3() {a3.call(this,"ww");this.age=29; }
var instance4=new b3();
console.log(instance4.name);//ww
console.log(instance4.age);//29
//这个例子说明构造函数继承可以传参数
特点:
- 解决了原型链继承中,子类实例共享父类引用属性的问题
- 创建子类实例时,可以向父类传递参数
- 可以实现多继承(call多个父类对象)
缺点:
- 实例并不是父类的实例,只是子类的实例
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
- 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
3.组合继承
function a4(name) {this.name=name;this.color=[1,2,3,4]; }
a4.prototype.sayName=function(){console.log(this.name);}
function b4(name,age) { a4.call(this,name);this.age=age; }
b4.prototype=new a4();
b4.prototype.constructor=b4;
b4.prototype.sayAge=function(){console.log(this.age);}
var instance5=new b4("aa",12);
instance5.color.push(5);
console.log(instance5.color);//[1, 2, 3, 4, 5]
instance5.sayAge();//12
instance5.sayName();//aa
var instance6=new b4("bb",22);
console.log(instance6.color);//[1, 2, 3, 4]
instance6.sayName();//bb
instance6.sayAge()//22
var instance5=new a4("aa");
instance5.sayAge();// not a function
//这个输出说明b4.prototype=new a4(),然后b4.prototype.sayAge增加了prototype的方法,但是
//增加的方法并没有增加到a4上面
特点:
- 弥补了构造继承的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
- 既是子类的实例,也是父类的实例
- 不存在引用属性共享问题
- 可传参
- 函数可复用
缺点:
调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
4.原型式继承
//object的结果的_proto_=o
function object(o){
function F(){};
F.prototype=o;
return new F();
}
var person={name:"wwwwwww",age:[1,2,3]};
var anp=object(person);//anp._proto_=person
anp.name="er";
anp.age.push(99);
var ynp=object(person);
ynp.name="ll";
ynp.age.push(100);
console.log(person.age);//[1, 2, 3, 99, 100]
//输出结果说明属性共享这一问题
//----------------//
var person2={name:"wwwwwww",age:[1,2,3]};
var anp=Object.create(person2);
anp.name="er";
anp.age.push(99);
var ynp=Object.create(person2);
ynp.name="ll";
ynp.age.push(100);
console.log(person2.age);//[1, 2, 3, 99, 100]
//这里说明用create方法一样可以完成原型式继承
缺点也是来自原型对象的引用属性被所有实例共享
5.寄生式继承
function createAnother(original) {
var clone=object(original);//clone._proto_=original
clone.sayHi=function(){ //扩充了方法
console.log("hi");
};
return clone;
}
var per={name:"loud",age:[1,2,3]};
var pp=createAnother(per);
pp.sayHi();
缺点和构造函数继承一样,都是每次创建对象都会创建一遍方法,内存占用大
6.寄生组合式继承
//inheritPrototype执行的结果是b5.prototype._proto=a5.prototype,b5.prototype.constructor=b5
function inheritPrototype(b5,a5) {
var prototype=object(a5.prototype);
prototype.constructor=b5;
b5.prototype=prototype;
}
function a5(name) {
this.name=name;
this.color=[1,2,3];
}
a5.prototype.sayName=function(){
console.log(this.name);
}
function b5(name,age) {
a5.call(this,name);
this.age=age;
}
inheritPrototype(b5,a5);
b5.prototype.sayAge=function(){
console.log(this.age);
}
var instance7=new b5("dd",99);
instance7.sayName();
其实寄生组合继承我觉得可以理解为组合继承的改进,和组合继承相比,避免了new a5()的写法,同时又保持了原型继承关系
特点:
只调用了一次构造函数,并且避免了在 prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用 instanceof 和 isPrototypeOf。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
缺点:代码比较复杂
参考文档:JS继承的实现方式
————————————————
版权声明:本文为CSDN博主「小幽艾」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/loisandyu/article/details/83046950