javascript之继承

268 阅读2分钟

本文内容,取自《Javascript高级程序设计》第三版,第六章

继承

继承主要靠原型链实现的。

原型链基本思想:利用原型让一个引用类型继承另外一个引用类型的属性和方法。原型链的构建是通过将一个类型的实例赋值给另外一个构造函数的原型实现的。

构造函数、原型、实例之间的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。

原型式继承

function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
}
function SubType(){
    this.subproperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
    return this.subproperty;
}

var instance = new SubType();
console.log(instance.getSuperValue()) //true

继承实现的本质就是重写原型对象。SubType.prototype等于SuperType的实例,实现SubType继承SuperType。

getSuperType()方法仍然还在SupertType.prototype中,而property则位于SubType.prototype中,因为property是实例属性,getSuperType()方法则是一个原型方法。instance属于自己的属性subproperty。

问题:SubType的原型被完全重写,SubType原型中的constructor属性不再指向SubType构造函数(指向了Base构造函数)

所有函数的默认原型都是Object的实例。

组合式继承

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.constructor = SubType;//能够识别是谁创建的对象
SubType.prototype.sayAge = function(){
    console.log(this.age);
}

var instance1 = new SubType('zhangsan', 25);
var instance2 = new SubType('lisi', 26);

instance1.colors.push('green');
console.log(instance1.colors) //['red', 'blue', 'green']
console.log(instance2.colors) //['red', 'blue']

原型链缺点:

第一,包含引用类型值的原型,修改问题;

第二,在创建子类型的实例时,不能向超类型的构造函数传递参数。

构造函数的缺点:

第一,不能识别出来是谁创建的;

第二,不能实现共享函数方法。

使用组合继承,避免了原型链和构造函数的缺点,融合他们的有点优点。

寄生组合式继承

上面的模式有个问题,有两组name和colors属性,一组在实例上,一组在SubType原型中。这就是调用两次SuperType的结果。

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;
}
inheritPrototype(SubType, SuperType)//原型
SubType.prototype.sayAge = function(){
    console.log(this.age);
}
function inheritPrototype(subType, superType){
    var prototype = Object(superType.prototype);//
    prototype.constructor = subType;//能够识别是谁创建的对象
    subType.prototype;
}

寄生组合式继承,通过构造函数实现继承属性,通过原型链实现继承方法。基本思路:不必为了指定子类型的原型而调用超类型的构造函数,我们需要的无非就是超类型原型的一个副本而已。

总结:

所有函数的默认原型都是Object的实例。

原型链的构建,是通过将一个类型的实例赋值给另一个构造函数的原型实现的。

原型链继承共享的属性和方法,通过借用构造函数继承实例属性。