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

Javascript原型链式模型分析

2014-06-17 17:20 169 查看
javascript中最难理解的就是原型链式模型,在写这篇文章前我也找过一些文章,发现都没有写的特别清晰,所以自己做了一些实践,有了一些更加清晰的理解,于是有了这篇文章。

一、基于原型OOP和基于类的OOP

在面向对象的编程中我们经常见到的是基于类的OOP,例如一些静态语言像C++,java,以及多数的动态语言,例如Python,PHP等等,据说javascript是唯一采用原型链式模型来实现OOP编程的。

基于类的OOP很好理解,类可以是一段描述块,也可以是其他类似的东西,但不需要有属性和方法,类可以产生实例,而实例拥有类中描述块描述的属性和方法。由于这种方式中类、对象、方法三者是区分的很开的,类不是对象,方法也不是对象。类中的继承关系通过某些关键字指定,例如java中的extends,非常明确并且简单。因此很好理解

基于原型的OOP理解起来相对困难,因为javascript中函数也是对象,实例也是对象。并且javascript中的继承是基于对象的。

二、原型链

在javascript中,原型链其实就是一条访问成员或者方法的搜索链式路径。从原型链的最底层一直向上搜索直到原型链的顶层也就是基于类的OOP中的基类。

原型链通过__proto__属性完成链接,例如

<script type="text/javascript">
function Base(){
this.a = 1;
this.b = 2;
}

function MyBase(){
this.a = 3;
this.c =5;
}

MyBase.prototype = new Base();
mb = new MyBase();
console.log(mb.a);
console.log(mb.b);
console.log(mb.c);
</script>
Hello World!


这段代码其实完成了一个继承过程,需要注意的一句就是MyBase.prototype = new Base(); 这句话的意思是MyBase的父对象是通过new关键字实例化的Base对象,

而new其实做了四件事:

1) 如果该函数对象的prototype为null,则生成一个新的原型对象,默认新的原型对象的都是通过new Object()生成的一个Object实例,并将prototype属性设置为该新原型对象,否则使用已有的原型对象;

2)将生成的原型对象的constructor属性设置为this,这里的this即代表该函数对象

3)生成一个空实例对象,将该对象的__proto__属性设置为函数对象的prototype属性指向的对象。

4)将该空实例对象作为this,去调用constructor

这段代码中,MyBase访问a,c的时候直接在底层的MyBase中找到了,所以输出分别是a = 3, c = 5,而访问b时在底层的MyBase中找不到该属性,因此沿着__proto__属性指向的对象进行搜索,由3)可知__proto__属性指向MyBase.prototype,而MyBase.prototype是new Base()得到的Base实例对象,因此在Base实例对象中寻找,找到,故返回b=2



三、 Function函数对象和Object函数对象



上图很好的说明了Function函数对象和Object对象在原型链中的关系,首先很多博客经常提到如下问题:

1、原型链中的Function和Object,并且说Object在更底层,因为在扩展了Object.prototype扩展了某属性之后,Function也拥有了该属性

2、Object instanceof Function为true和Function instanceof Object都成立,怎么理解?

其实看了上图就不难理解了。

第一,关于谁在最底层的问题,由于Function和Object在链式关系中是相互联系的,如果可以看出谁是根据谁生成的自己这个函数对象,那么可以说后者是前者的底层对象。

对于这个问题,通过观察上体,只提供了一条线索,那就是Object.__proto__ = ==Function.prototype,而Function.__proto__===Empty function !== Object.prototype

所以可以大概猜测,Object函数对象的生成是通过new Function(),此时新对象的prototype还是undefined,没有定义,所以需要为新对象指定prototype为内置生成的顶层对象(root),而顶层对象是构造器为Object函数对象的空的对象。这样Object函数对象变产生了。但是这只是一种推测可能的情况,具体实现和javascript引擎有关。

第二,Object instanceof Function 为true是因为 A instanceof B返回true当且仅当A的原型链中包含了B.prototype,这也是根据原型链来进行判断的,而上图中,很显然,有Object.__proto__==function Empty(){} == Function.prototype;而Function instanceof Object,也同样的从上图中可以看出,Function.__proto__==function Empty(){}.

function Empty(){}.__proto__==Object.prototype,因此满足。

终于写完了,畅快!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息