(Javascript是ECMAScript的一种方言,在下面的描述中,不做区分。)
Javascript是一种面向对象语言,其但和C++、Java这种OO语言不同,JS的OO是通过原型链来实现。关于JS的原型链,已经有很多的文章描述过了。在这里描述的,则是关于Javascript中Function与Object的原型链的关系。
当我们谈论Javascript中的“对象”时,不仅仅是Object,因为它本身也是对象的一种。在Javascript的基本类型(undefined、boolean、null、string、number、object、symbol)中,object指的是我们一般意义上的“对象”,是一种类型,而不是我们在这里要说的Object类型的对象。
在Javascript基础对象中,有一些是最常用的,包括Object、Function、Array、Date。它们都是对象,那么他们的关系是怎样的呢?(在这里,我们探讨一下Object与Function的关系)
记得以前,有人跟我讲过,说Object和Function是互相继承。感觉说的好像很有道理呢。Object是函数,Function是对象。实际上,他们并非相互继承。
对于Object和Function,我们一般指的是他们的构造函数,因为global object(全局对象,在浏览器环境指window)的Object和Function属性的初始值,就是Object constructor和Function constructor。
对于Javascript对象,标准定义了许多的内部槽(internal slot
),比如[[prototype]]
,我们可以通过__ptoto__
属性来访问。这和prototype
属性并不是一个概念。而这正式Javascript的原型链的实现基础。
关于Object和Function的关系,我们可以用下面这样一张图来进行描述。
如图所示,对象原型链的尽头是null
,这并不意外。箭头指向的地方,是属性关系。而以%包裹的是Javascrpit的固有对象(intrinsic object)。从图可以看到,有两个很重要的固有对象:
%ObjectPrototype%
%FunctionPrototype%
这两个固有对象,通过一定的属性包含关系,形成了Function与Object的拓扑图。需要说明的一点的是,%FunctionPrototype%
对象没有prototype
属性。
Function和Object并非相互继承,它们都有一个共同的祖先,%ObjectPrototype%
,这才导致了他们有一些共同的属性和性质。
那么,为什么Object又是函数呢?很简单,Javascript对象,有[[call]]
和[[constructor]]
内部槽,它们决定了js对象是否为callable、以函数进行调用时的行为、是否可为构造函数、以构造函数进行调用时的行为。
PS: 对于图上的关系,我们可以用以下代码做简单的验证
1 | Function.prototype === Function.__proto__ |