最近在看《javascript设计模式》,有关类式继承自己感觉比较难于理解,于是乎查找了相关资料,整理如下。
1.关于函数对象引自http://cssrain.cn/article.asp?id=1371
让我们来看看函数对象和普通对象有什么区别。我们前面说过,对象就是无序的属性集合,那么函数的属性和普通对象的属性有什么不同呢。根据ECMA-262中的13.2节所述,在函数对象创建时,系统会默认为其创建两个属性[[call]]和[[constructor]],当函数对象被当做一个普通函数调用的时候(例如myFunc()),“()”操作符指明函数对象的[[call]]属性就被执行,当他被当做一个构造器被调用的时候(例如new myConst()),他的[[constructor]]属性就被执行,[[cosntructor]]的执行过程我们将在下一节中介绍。除此之外,当一个函数被创建时,系统会默认的再为其创建一个显示属性prototype,并为其赋值为
this.prototype = {constructor:this}
具体内容可以参加老道的那本书的第五章。这个函数对象的prototype属性也是为了js把函数当做构造器来实现继承是准备的,但是这个属性是可以在js脚本中访问和修改的。在这里要强调的一点是,大家一定要区分对象中的[[proto]]属性和函数对象中的prototype属性(《javascript设计模式》中说每个对象都有一个原型对象,但这并不意味着每个对象都有一个prototype属性,实际上只有函数对象才有这个属性。在创建一个对象时,javascript会自动将其原型对象设置为其构造函数的prototype属性。),我在刚开始学习的时候就是因为没有很好的区分这两个东西,走了很多的弯路。
2.构造器创建函数的过程
下面我么来详细说明构造器创建对象的过程:
第一步,先创建一个空的对象(既没有任何属性),并将这个对象的[[proto]]指向这个构造器函数的prototype属性对象
第二步,将这个空的对象作为this指针传给构造器函数并执行
第三步,如果上面的函数返回一个对象,则返回这个对象,否则返回第一步创建的对象
第四步,把函数当做一个类来使用
一般来说函数对象的prototype指向的是一个普通对象,而不是一个函数对象,这个普通对象中的属在由此函数构造器创建的对象中也可以访问。
每个函数的prototype对象中总是含有一个constructor属性,这个属性就是连接到我们的这个函数本身。再加之,有这个函数生成的每个对象的[[proto]]属性都是指向构造器函数的prototype对象,所以通过[[proto]]链,每个由构造器函数生成的对象,都有一个constructor属性,指向生成他的构造器函数,因此我们可以通过这个属性来判断这个对象是有哪个构造器函数生成的。
3.如何实现类式继承
这里有几点需要说明的是
1.为什么要subClass.prototype.constructor = subClass;
定义一个构造函数时,其默认的prototype对象是一个Object类型的实例,其constructor属性会被自动设置为该构造函数本身,如果手工将其设置为
另一个对象,那么新对象自然不会具有原对象的constructor值,所以需要重新设置其constructor属性。
2.为什么要设置一个空函数var F = function() {};,而不是直接subClass.prototype=Superclass.prototype。
原因和上述的差不多,如果这样的话,那么这样会使subclass和Superclass的prototype指向同一个对象,在使用supclass和subclass的过程,会产生一些
不可预知的效果。通过一空函数实现继承,不然,修改/扩展subClass.prototype就会影响到superClass.prototype。同时也会覆盖了Superclass.prototype.contructor属性。,使其指向subclass.
3.最后三行代码则用来确保Superclass.prototype.constructor属性已被正确设置(即使Superclass就是Object类本身)
(本文没有区别大小写,请注意)