您的位置:首页 > Web前端 > JavaScript

JavaScript OOP:继承与原型链

2018-01-31 16:18 288 查看

0、继承

OOP中最重要的特性之一就是继承,大部分OO语言都支持两种继承方式:

接口继承:只继承方法的签名
实现继承:继承实际的方法

JavaScript的函数没有所谓的签名,因此只支持实现继承,而实现继承主要是依靠原型链实现的。

1、原型链

JavaScript原型链的基本思想是:利用原型让一个引用类型继承另一个引用类型的属性和方法。
首先看一下构造函数原型实例三者的关系:

每个构造函数都对应一个原型对象
原型对象中都包含一个指向构造函数的指针
每个实例中都包含一个指向原型对象的指针

以构造函数Person()、原型Person prototype和实例person1为例,三者关系如下图所示:



如果让原型对象等于另一个类型的实例会怎样?
此时的原型对象会包含一个指向另一个原型的指针,相应地另一个原型中也会包含一个指向其对应构造函数的指针。这时就相当于把两个类型“链接”了起来。那么继续考虑,若另一个原型也等于另一个实例,上述关系依然成立。层层递进的实例与原型的链式关系就构成了所谓的原型链。
我们举例说明这种链式结构:
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

关系图如下:



上例中定义了两个类型:SuperType和SubType。每个类型分别有一个属性(构造函数中)和方法(原型中)。
SubType继承了SuperType,继承的方式是:创建一个SuperType的实例,并将SubType.prototype指向该实例。本质就是将子类的原型对象替换为父类的实例。

经过这种替换,原来存在于SuperType的实例中的所有属性和方法,现在就在SubType的原型Subtype.prototype中(上例中父类的property属性和getSuperValue()方法),继承关系由此确立。我们也可以给子类添加新方法和属性(上例中getSubValue()方法)。

再来梳理一遍继承的流程:为了让SubType继承SuperType的属性和方法,我们未使用SubType默认的原型,而是为其换了一个新原型:一个SuperType的实例。而这个新原型作为一个SuperType的实例拥有SuperType的全部属性和方法,并且其内部指针[[prototype]]指向SuperType的原型。这样通过instance可以调用SuperType的property属性和getSuperValue()方法(注意property属性是一个实例属性,getSuperValue()方法则是原型方法)。

2、默认原型

JavaScript中所有引用类型默认继承自Object,而这个继承关系也是通过原型链实现的。所有类型的原型都是Object的实例,因此默认原型中都会包含一个指针,指向Object.prototype。正是通过这种机制,所有的自定义类型都会继承toString()、valueOf()等默认方法。

因此上例中原型链还不完整,缺少一个Object的继承层次。将其原型链补全如下图:



总之,SubType继承自SuperType,而SuperType又继承自Object。假如调用instance.toString()方法,实际上就是在调用Object.prototype中的方法。

每当调用实例中的方法或属性时,就会进行一次搜索过程:首先搜索本实例,若没有找到则搜索该实例的原型。而原型链的本质就是:扩展了原型搜索机制。调用instance.toString()方法时经历了:搜索instance;搜索SubType.prototype;搜索SuperType.prototype;搜索Object.prototype。直到搜索到属性或方法才会停止,若是找不到则会搜索到原型链的末端停止。

3.确定原型和实例的关系

总结一下如何确定原型与实例间的关系。共有两种方式:

instanceof操作符
isPrototypeOf()方法

instanceof操作符测试实例和原型链中出现过的构造函数
console.log(instance instanceof Object); //true
console.log(instance instanceof SuperType); //true
console.log(instance instanceof SubType); //true
而isPrototypeOf()方法测试实例和原型链中出现过的原型
console.log(Object.prototype.isPrototypeOf(instance)); //true
console.log(SuperType.prototype.isPrototypeOf(instance)); //true
console.log(SubType.prototype.isPrototypeOf(instance)); //true


参考资料《JavaScript高级程序设计(第3版)》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: