原型链的最底层:Object、Function、根对象

1,515 阅读4分钟

原型链的最底层:Object、Function、根对象

这是JavaScript比较奇葩的一个地方,也是不太让人容易接受的一点。

我们知道一般任何对象都是Object的instance,因为原型链的顶端都指向Object.prototype。那么Object本身是什么?Object也是个函数,而任何函数都是Function的实例对象,比如Array,String,当然Object也包括在内,它也是Function的实例,即:

Object.__proto__ === Function.prototype;
Object instanceof Function === true

同时,Function是个对象,它的原型是Function.__proto__,指向Function.prototype,并且这个原型链向上继续指向Object.prototype,即:

Function.__proto__.__proto__ === Object.prototype;
Function instanceof Object === true

这样就有了一个JavaScript里经常说到的蛋鸡问题:

Object instanceof Function === true
Function instanceof Object === true

到底谁先谁后,谁主谁次?关于这一点网上已经有很多解释,这里首先陈述我的观点,是先有Function,它是主;后有Object,是次。以下是我个人的理解,可能并不准确。要看待这个问题,我们可以从JavaScript创造世界开始想象:

  1. 我们知道Object.prototype是原型链的root。但首先,现在世界上还没有Object,更没有Object.prototype。现在只有个特殊的对象,姑且称它为root_prototype,里面定义了些基本的field和method比如toString之类的,以后我们要让所有的原型链都最终指向它。注意它没有原型,它的__proto__是null,这也是它和所有其它JavaScript对象的区别,使它与众不同,能有资格成为原型链的root。
  2. 然后定义Function。先看Function的prototype,我们只要知道这是一个特殊的对象,它的原型__proto__指向刚才的root_prototype,就是说Function.prototype.__proto__ === root_prototype,这样它就算连上了原型链的root。
  3. 上面已经讲过了,Function也是个对象,也有__proto__,指向Function自己的prototype,Function.__proto__===Function.prototype,所以说白了Function也是个奇葩,是JavaScript里规定的一个特殊的东西。而Function.prototype的原型__proto__继续指向root_prototype,所以Function也连上了原型链root。
  4. 所有的函数,什么Array之类的,包括Object也是函数,都是继承Function的,就是说,任意函数foo.__proto__ === Function.prototype,所以我们自然有Object instanceof Function。
  5. 然后再看Object,它本来就是个函数而已,和其它函数没什么区别,都继承了Function,Object.__proto__ === Function.prototype //true。可是现在最关键的一步是,强行设定让Object.prototype = root_prototype,这样Object.prototype就成了原型链的root!注意这里的逻辑,是先有了root_prototype,然后规定Object.prototype等于它,这一步是人为规定的,这就是Object的特殊之处。
  6. 好了现在Object.prototype === root_prototype了,成了所有对象原型链的root。那么由第3步的结论,Function也是对象,是连上了root_prototype的,而现在root_prototype给Object.prototype了,那Function自然就是instanceof Object。
总结一下:
- 首先没鸡没蛋,先有一个特殊对象root_prototype,它是上帝。
- 接下来应该是先有Function,并且定义它的prototype和__proto__,都连上了root_prototype。
- 然后才有了Object,它是Function的instance,继承了Function。这时候Object仍然只是个普通的函数。
- 然后规定Object.prototype = root_prototype,这时候Object才开始显得特殊,成为了原型链的顶端,否则它和其它函数根本没什么区别。
- 于是所有的东西,包括Function,都成了Object的instance了。

这里要强调Object和其它函数的不同之处。Object之所以特殊,就是因为Object的prototype被设定为了root_prototype,仅此而已;而其它函数例如foo,它的prototype只是一个普通的对象,这个对象的__proto__默认情况下指向root_prototype。至于为什么这样设定,为什么Object会特殊化,大概只是因为Object这个名字起得好,而foo,bar没那么特殊。所以说白了Object函数只是一个盛放root_prototype的容器而已,从而使它晋升为一个特殊的函数。

另外值得注意的是,obj instanceof function 并不意味着obj就是这个function创建出来的,只不过是obj的原型链上有function.prototype而已。

所以所谓的 Object instanceof Function 和 Function instanceof Object 的蛋鸡问题,前者应该来说是自然而然、不容置疑的,可以认为Object函数是Function创造出来的;而后者说白了只是因为强行规定了Object函数的特殊性,而导致的一个推论,而Function并非是Object创建的。

版权声明:

本文摘自JavaScript原型链以及Object,Function之间的关系--hyuan