首先,JavaScript被称为“入门容易精通难”的一门语言。对于学习JavaScript并使用开发并不困难。但JavaScript作为一门面向对象的语言,它又与Java之类的有所区别。Java是一门class-based language(基于类的面向对象语言),而JavaScript是一门prototype-based language(基于原型的面向对象语言)。而prototype-based相对于class-based更为抽象,class-based简洁明了,类和对象。类为模版,生成对象。Prototype-based则没有类这么一说,在很多书籍中,为了方便读者理解,通常把JavaScript中的构造函数用来模拟一个类。但易于理解的同时,也会带来更多的疑惑。我也是如此。
prototype-based(基于原型)又是什么呢? 一般在学习JavaScript过程中,为了让初学者便于理解,有那么一句总结的话:“在JavaScript中,所有都是对象,函数也是对象。顶层有Object和Function两个对象”。那么,它们之间有什么关系呢?
先来说说new的含义,假如有那么一个构造函数叫Person,当new一个对象时,例如:
<span style="white-space:pre"> </span>var p = new Person();
那么总结就是做了那么一件事
,
把
Person
函数中的
prototype
给新生成的对象
p
的
__proto__
。每个函数对象都有一个属性叫
prototype
,它指向另一个对象,也就是说,如果以这个函数作为构造函数来
new
一个对象,那么这个构造函数中的
prototype
指向的对象就是新生成对象的原型。而
__proto__
为每个对象都拥有的属性
(
注
:
对象,包括函数对象
).
在JavaScript中,Object、Function都既是对象也是函数,如何理解呢?首先,你可以写这么一些代码:
<span style="white-space:pre"> </span>var obj = {};
<span style="white-space:pre"> </span>alert(obj.constructor);
如果你用
chrome
、
firefox
打开,你会得到这样的提示
: function Object() { [native code] },
首先解释一下
,native code
意思是底层代码,一般情况下
c/c++
完成的内容,我们不管。
obj.constructor
表示这个对象所对应的构造函数。我们创建的是一个空
object
对象,得到的
constructor
是
Object()
。应该没有疑问吧
?
好,我们继续。再写这样的代码
:
<span style="white-space:pre"> </span>var hello = function(){ };
<span style="white-space:pre"> </span>alert(hello.constructor);
得到结果为
: function Function() {[ native code]},
发现问题了吗?其实这两次我们得到的
Object()
和
Function()
,其实就是我们之前说的那两个顶层对象
(
目前暂且认为顶层
,
后面会补充
)
。那么,前面提到了,每个函数对象都有一个
prototype
属性
,
指向原型对象。那么
Function()
和
Object()
这两个函数中,必须有那么一个属性,那么我们称它们为
Function.prototype
和
Object.prototype
。
再来写这么写代码
:
<span style="white-space:pre"> </span>alert(Function.constructor);
<span style="white-space:pre"> </span>alert(Object.constructor);
得到结果为同样的
: Function() {[ native code]},
这是什么意思呢
?
刚刚我们说的两个顶层对象的构造函数,都为
Function,
那也就是说,
Object
和
Function
都由
Function
构造出来的
,
而一般最有疑惑的就是
Function
由
Function
构造出来。为什么呢
?
其实很简单,可以这么理解
:
既然
Function
是一个
native
函数
,
那我们就认为它可以帮我们生成所有的对象,但每个对象类型,属性不一样,怎么标识呢
?
很简单,之前说的
prototype
派上用场了
,
就是它。
如果觉得抽象,请看图:
我们所说的Function和Object,其实都是引用名称。堆空间的Function就是生成对象的核心。再来看看,黄色的箭头表示Function引用和堆空间的Function()函数的关系,Function函数中prototype, __proto__与Function.prototype、Object.prototype的关系。红表示Object与Function()函数关系.
可以认为,Object.prototype为Function.prototype中的一个小零件,如果包含Object.prototype,它就是一个对象。而若包含Function.prototype则可以认为它就是一个函数.重点先看Function(native code),通过上文,我们都知道所有对象都由它生成,那么之前所说的Function对象,我们可以这么认为,它是通过这个Function(native code),把其中的prototype指向Function.prototype,或者说,把Function.prototype组装到Function(native code)函数的prototype属性中,然后__proto__指向Function.prototype。经过这么一折腾,所得到的东西,我们不给它新名字,还叫Function(native code),但与组装之前的已经不一样.我们用这个组装完成后的新Function,进行new Function(),那么得到的这个对象,我们就把它赋值给Function引用。同理,通过原先的Function(native code),对里面的prototype和__proto__进行组装,我们也可以得到另一个新的Function,但为了区别,我们改名叫Object(native code),这就是我在上文中(本文第四段),提到的function Function() { [native code] },function Object() { [native code] }。
最后,说到这里,其实之前所说的顶层对象Function和Object,其实指的就是通过图中Function(native code)所生成的两个对象,说其为顶层对象其实并不是百分百准确,因为它们上面依然存在Object.prototype和Function.prototype这两个最原始的对象,它们才是顶级。但对于我们开发来讲,可以认为Function和Object这两个对象是顶层,因为我们生成对象,与之直接打交道的,就是Object和Function,而不是Object.prototype和Function.prototype。