Javascript对象,prototype链

Doc链接: http://docs.google.com/Doc?docid=0AZUdXGtQa0xqZGRocmo3MzZfMjA2Y2ZqZ2szZ2g&hl=en

关键词:JavaScript;对象;prototype;prototype链

我们来打个比方吧:
随着个人电脑硬件的白菜价化,很多硬件制造商开始帮用户做整机DIY。有时候用户可能回到“总部”去装机,那里东西很全。但一般这些厂家在各个小地方也有网点,你可以就近去装机,他也提供所有的配件。但这里这些网点自己并没有配件,而是当用户要的时候他们便去总部拿,有些硬件总部也没有,这时总部在向生产商拿... 最终可能会到生产流水线上。但这一切对装机的人来说是不需要关心的,他只知道你是装机网点,我要什么东西(当然局限在电脑硬件)你都能提供。同时这些厂家也不会在任何一个网点放置所有的硬件,只是有需要的时候会向上一级取。
这套东西就是我要说的JavaScript中的对象到底是怎么工作的:prototype链,就像这种硬件供应商不断向自己的上一级去取一样的效果。

如果你不想关系OOP(面向对象编程)的话,完全没必要去关心这个话题。(这里能不能叫OOP以后再理解吧)
首先还是要说一下js的原生对象,包括:Array、Number、RegExp、Function、Object... 这里不一一列举的,列举这些东西的文档到处都是。
当我们用这些原生对象的时候可以理解为他们就是系统提供的“类”,我们可以这样定义一个对象:



这里就可以理解我们创建了一个Object类的实例obj。obj可以使用Object的方法obj.toString()等等。
这一切“长的”都很像Java、c++那样的类、实例的行为。但我们在下面将看到,其实不是这样的...

js是一个prototype语言
prototype(原型),如果你知道这个概念,那是最好。如果不知道,我这里会做一些介绍,但不是官方的,深入的理解请看其他资料。
prototype,prototype,prototype,prototype,prototype,prototype,prototype ...
先把他背下来吧,prototype到底干啥的?原型?不理解... 没关系,记住它

这里我先声明几点(不一定正确,但对你当前理解下面的行为会有很好的帮助,当看不懂的时候就来看这几条)
1. js里没有“类”这一概念,是根本就没有。
2. js里的最常用的东西就是Object(以下都称为对象),他有点像一个hash map,一个键值对集合,一般我们习惯写成:

我们可以用obj.str或者obj['str']来访问这些属性

3. js里函数也是对象,但是他又可以执行函数的行为...

 

继续说prototype,如果你做的东西较多,应该听说过这个东西“copy-on-write”,什么意思?看下面的代码:


这样有什么好处?一方面是节省内存(特别是对大对象来说),如果一个obj,有很多变量只是读他,那就不用去为每个变量都开一个这样的空间。只有有变量想写的时候再给他一个copy让他去摆布。
另一方面可能也节省了copy对象的时间吧。这个思想应用很广泛。
来个图说明一下吧:
copy-on-write

大哥,咋又跑题啦... ok,咱来继续讲prototype
prototype的思想和这个有点像,稍微变化了一点。原型,原型,就是我每次造东西的时候都用一样的东西去生产他,当然造出来都一样,
好,那我们来剖析一些 var obj = new Object(); 都做了啥。
首先我们说Object是一个东西,他可以用来制造东西,而且按照自己的意愿(模板、原型)去造这个东西。那我们来看看他的模板吧,他存在哪里的?就存在prototype里的
每个js的原生对象都有自己的一个prototype(都有一个指针叫prototype指向这个原型的空间),每次用他们去创建新东西,他们都会用原型给你造一个。
比如Object,他就有个指针Object.prototype指向的就是他的原型(是我们上面说的那种键值对集合)
alert(Object.prototype.toString); 这个就可以显示他原型里的toString是啥(一个函数)

btw:用过js的同学可能会有这样的想法,js不是有反射么,咱来个for i in Object.prototype来看看他都有啥,想法很好,不过你啥也看不到 (why?js让一些原生的方法有个DontEnum,就是不让你for in出来的。请搜索“js DontEnum,或往下看)

画个图吧
prototype

OK,那用Object来创建一个对象,是不是就把prototype的这些属性都塞到这个新对象里?不是,这里就用到了copy-on-write的思想,注意是思想
obj如何去拥有Object.prototype里的属性?那也设置的指针来指向这块空间呗,js里确实是这样做的,而且这个指针的名字叫__proto__(两个下划线,这个据说是方便大家debug用的,不推荐直接使用。下面我们还会看到一种标准的写法)。
我X,这么那啥的名字... 至少我看到的第一反应就是这个,第二反应是那我为什么可以用obj.toString(),而不是obj.__proto__.toString() ? 是的,你都可以用,而且效果一样,但忘下看,你应该能区分这两写法的不同之处。
__proto__是个特殊的属性(记住它),别在乎他为什么叫这个名字。那他能帮我们做什么呢?这就是传说中的prototype chain... (prototype链)
当一个对象去读自己的一个方法或属性是(以下统称属性,方法也是个属性,一个指向函数的属性),他首先会看自己有没有,没有的话会沿着__proto__向上找,直到找到或者__proto__ == NULL。(js就这样的行为,记住它,想问为什么就去深入了解他)
这就解释了我们为什么可以用obj.toString()...

OK对Object的prototype就说这么多,毕竟他是原生对象,提供的方法也不多,而且还不可见,就不拿他举例了。不过对


还有一点要说,当我们去“读”一个属性时,没关系,查__proto__链。但当我们去“写”一个属性的时候呢?copy-on-right,把Object.prototype copy一份,然后在里面放个x属性。NO!
不需要这么麻烦了,因为Object.prototype是我们可以用obj.__proto__去获取的,我们只有给obj的空间上塞个x就可以了。这两句话执行过后的效果如下:
__proto__

现在你还能认为js里的new和Java、c++里的new做了相同的事情吗?

===============简陋的分割线====================

回到第一句,咱可是想用js来做OOP的,别管你啥方法,看起来像OOP,能有OOP的特性就行了。OK,那就要来看看js里怎么来定义类了,不是说没有类么?是的,没有,但可以来模拟 :)
今天有点晚了,再不闪就没公交车又要走6公里了,未完待续。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章