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版)》
相关文章推荐
- JavaScript 面向对象与原型、继承
- 一种javascript链式多重继承的方式(__proto__原型链)
- JavaScript原型与继承
- 一个JavaScript上的OOP编程技巧:继承
- JavaScript的原型继承
- 浅析Javascript原型继承 推荐第1/2页
- Javascript--原型链实现继承
- javascript中继承(一)-----原型链继承的个人理解
- 浅谈javascript的原型继承
- JavaScript继承基础讲解(原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承)
- JavaScript继承基础讲解(原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承)
- Javascript 原型和继承(Prototypes and Inheritance)
- javascript 为什么原型继承很重要
- JavaScript原型、函数伪装(apply,call)、继承
- javascript原型链和继承
- 个人觉得很好理解的JavaScript原型和继承
- Effective Javascript 阅读笔记(6)-Javascript 原型链继承
- javascript——混合继承(借用构造函数+原型继承)
- 闲聊javascript继承和原型
- 【面试必备】javascript的原型和继承