大致有6种继承,各有利弊吧
- 原型链继承
- 盗用构造函数
- 组合继承 【原型链 + 盗用构造函数】
- 原型式继承 【适用于不需要单独创建构造函数,但仍需在对象之间共享信息的场合】
- 寄生式继承 【寄生构造函数+工厂模式】
拷贝原对象、增强副本、返回 - 寄生式组合继承
<1> 原型链继承
让儿子构造函数的原型等于父亲的实例对象
Child.prototype = new Parent();
缺点:
- 所有实例共享同一个引用类型的属性
function Parent () {
this.names = ['kevin', 'daisy'];
}
function Child () {
}
Child.prototype = new Parent();
var child1 = new Child();
child1.names.push('yayu');
console.log(child1.names); // ["kevin", "daisy", "yayu"]
var child2 = new Child();
console.log(child2.names); // ["kevin", "daisy", "yayu"]
- 在创建 Child 的实例时,不能向Parent传参
<2> 盗用构造函数
在儿子构造函数中调用父亲的构造函数,来实现父亲构造函数中的属性!!
注意:
- 方法都在构造函数中定义
function Parent () {
this.names = ['kevin', 'daisy'];
}
function Child () {
Parent.call(this);
}
var child1 = new Child();
优点:
- 避免了引用类型的属性被所有实例共享
- 可以在 Child 中向 Parent 传参
缺点:
- 每次创建实例都会创建一遍方法。(且继承不到父亲原型中的方法!!!!)
<3> 组合继承 【原型链+盗用构造函数】
使用
原型链继承原型上的属性和方法,使用盗用构造函数继承实例自己的属性!!!
注意:
- 此时就可以把方法定义到原型对象上了
function Parent (name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child (name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
var child1 = new Child('kevin', '18');
缺点:
- 效率问题,父类构造函数被调用了两次!!!
<4> 原型式继承 【不需要单独创建子类和父类构造函数的原型链继承,也不需要再 new 出来子类实例对象,直接可以得到实例对象】
实现对象间属性和方法的共享,不需要单独创建父类、子类构造函数,也不需要再 new 出来子类的实例对象。思路就是:
创建一个空的构造函数 F(),把该构造函数的原型指向要继承的对象。然后返回 new F()
function createObj(o) {
function F(){}
F.prototype = o;
return new F();
}
缺点:
- 所有实例共享同一个引用类型的属性
<5> 寄生式继承 【工厂模式:拷贝父对象,增强副本,返回副本】
基本思路类似于寄生构造函数和工厂模式:创建一个实现继承的函数,在函数中先拷贝源对象,然后增强副本,然后返回新对象!!
function createObj (o) {
var clone = Object.create(o);
clone.sayName = function () {
console.log('hi');
}
return clone;
}
缺点:
- 跟借用构造函数模式一样,每次创建对象都会创建一遍方法。
<6> 寄生组合式模式 【解决了组合继承,父类构造函数need new两次!!】
基本思路(1)父类方法继承: 不通过调用父类构造函数给子类原型赋值,而是获得父类原型的一个副本,就是用寄生式继承来继承父类原型,然后将返回的新对象赋值给子类的原型。(即把子类的原型指向父类的原型) (2) 父类属性继承:盗用构造函数来继承父类的属性!!!
function Parent (name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child (name, age) {
Parent.call(this, name);
this.age = age;
}
// 寄生式+原型式 继承方法
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function prototype(Child, Parent) {
var prototype = object(parent.prototype);
prototype.constructor = Child;
Child.prototype = prototype;
}
// 当我们使用的时候:
prototype(Child, Parent);