继承方式
很多其他面向对象语言都支持两种继承方式:
- 接口继承:只继承方法签名。
- 实现继承:继承实际的方法。
由于函数没有签名,ECMAScript只支持实现继承,而且其实现继承主要是通过原型链来实现的
原型链继承:让原型对象指向另一个类的实例
利用原型让一个引用类型继承另一个引用类型的属性和方法
让原型对象指向另一个类的实例,原型对象的
__proto__就是指向另一个类的原型,另一个类的原型的constructor就指向了另一个类
示例:SubType.prototype = new SuperType()
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType() {
this.subproperty = false;
}
//继承了SuperType
SubType.prototype = new SuperType();
//增加或覆盖方法必须放在替换原型的语句之后
SubType.prototype.getSubValue = function () {
return this.subproperty;
}
var instance = new SubType();
console.log(instance.getSuperValue()); //true
console.log(SubType.prototype); //{ property: true, getSubValue: [Function] }
instance.getSuperValue()步骤:
- 1、 instance 的私有属性和私有方法没有 getSuperValue
- 2、 通过
__proto__找到SubType.prototype的公有属性还是没有getSuperValue - 3、 因为SubType.prototype= new SuperType() 所以再次通过
SubType.prototype__proto__找到SuperType.prototype的公有属性getSuperValue - 4、 此时SuperType.prototype.getSuperValue中的this是instance
- 5、 instance 是 SubType的实例所以私有属性和私有方法没有 property
- 6、 通过
__proto__找到SubType.prototype的公有属性property输出true
SubType.prototype = new SuperType();原来SuperType的实例中的所有属性和方法(不管是似有还是公有的)现在也存在于SubType.prototype中了instance通过
__proto__指向 SubType.prototypeSubType.prototype通过
__proto__指向 SuperType.prototype
增加或覆盖方法必须放在替换原型的语句之后
缺点
1、 包含引用类型值的原型属性会被所有势力共享,这也是为什么要在构造函数内而不是在原型对象中定义属性的原因
2、 在创建子类型的实例时,不能向超类型构造函数中传递参数
借用构造函数(call、apply):继承的是私有属性
1、在子类型构造函数内部调用超类型构造函数(要继承的构造函数)
2、将超类型构造函数中的this变为子类型构造函数的实例对象
3、一般用call 、apply 来实现
function SuperType() {
this.colors = ['red','blue','yellow'];
}
function SubType() {
//继承了SuperType
SuperType.call(this)
//将SuperType中的this变为SubType的实例对象
}
var instance = new SubType();
instance.colors.push('black');
console.log(instance.colors); //[ 'red', 'blue', 'yellow', 'black' ]
var instance2=new SubType();
console.log(instance2.colors); //[ 'red', 'blue', 'yellow' ]
向超类型构造函数中传参:SuperType.call(this,name)
function SuperType(name) {
this.name = name;
}
function SubType(name) {
//继承了SuperType
SuperType.call(this,name)
}
var instance = new SubType('aaa');
console.log(instance.name); //aaa
缺点
仅仅使用借用构造函数的方法时,并没有继承 超类型构造函数原型上的公用方法,方法都在函数中定义,因此函数复用就无从谈起了
组合继承
使用原型链实现对原型属性和方法(公有属性和方法)的继承,使用借用构造函数来实现对实例私有属性的继承
- 使用借用构造函数来实现对实例私有属性的继承:SuperType.call(this,name)
- 继承公有属性和方法
- 设置constructor保证原型链完整性
function SuperType(name) {
this.name = name;
this.colors=['red','blue','yellow']
}
SuperType.prototype.sayName=function () {
console.log(this.name);
}
function SubType(name,age) {
//1、继承 私有属性
SuperType.call(this,name)
this.age=age;
}
//2、继承公有属性和方法
SubType.prototype=new SuperType();
//3、设置constructor保证原型链完整性
SubType.prototype.constructor=SubType;
//新增方法
SubType.prototype.sayAge=function () {
console.log(this.age);
}
var instance1 = new SubType('aaa',18);
instance1.colors.push('black')
console.log(instance1.colors); //[ 'red', 'blue', 'yellow', 'black' ]
console.log(instance1.name); //aaa
instance1.sayName(); //aaa
instance1.sayAge(); //18
var instance2 = new SubType('bbb',16);
console.log(instance2.colors); //[ 'red', 'blue', 'yellow' ]
console.log(instance2.name); //bbb
instance2.sayName(); //bbb
instance2.sayAge(); //16
缺点:多次调用超类型构造函数导致效率下降
寄生组合式继承
寄生式继承:创建一个仅用于封装继承过程的函数
该函数在内部以某种方式增强对象(设置constructor、新增方法等),最后再像真的是他做了所有工作一样返回对象
寄生组合式继承:
- 通过借用构造函数来继承属性,
- 通过原型链的混成形式方法继承方法,
- 使用寄生式继承来继承超类型的原型
基本思路:不必为了指定子类型的原型而调用超类型够造函数,只需要超类型原型的一个副本
本质:使用寄生式继承来继承超类型的原型,然后再将结果指定给值类型的原型
基本模块
//继承方法的函数
function inheritPrototype(subType,superType) {
//创建对象
var prototype = Object(superType.prototype);
//增强对象
prototype.constructor=subType;
//指定对象
subType.prototype=prototype;
}
寄生组合式继承成品
//继承方法的函数
function inheritPrototype(subType,superType) {
//创建对象
var prototype = Object(superType.prototype);
//增强对象
prototype.constructor=subType;
//指定对象
subType.prototype=prototype;
}
function SuperType(name) {
this.name = name;
this.colors=['red','blue','yellow']
}
SuperType.prototype.sayName=function () {
console.log(this.name);
}
function SubType(name,age) {
//继承 属性 (1)
SuperType.call(this,name)
this.age=age;
}
//调用继承方法 (2)
inheritPrototype(SubType,SuperType);
//新增方法
SubType.prototype.sayAge=function () {
console.log(this.age);
}
var instance1 = new SubType('aaa',18);
instance1.colors.push('black')
console.log(instance1.colors); //[ 'red', 'blue', 'yellow', 'black' ]
console.log(instance1.name); //aaa
instance1.sayName(); //aaa
instance1.sayAge(); //18
var instance2 = new SubType('bbb',16);
console.log(instance2.colors); //[ 'red', 'blue', 'yellow' ]
console.log(instance2.name); //bbb
instance2.sayName(); //bbb
instance2.sayAge(); //16