由一段代码引起的关于Object和Function的鸡和蛋问题的思考

做为一名前端开发者,咱们都知道JS是单继承的,而Object.prototype是原型链的顶端,全部对象从它继承了包括toString()、valueOf()等等公共属性。javascript

鸡和蛋问题的由来

首先ObjectFunction都是构造函数,而全部的构造函数都是Function的实例对象。 所以ObjectFunction的实例对象;而Function.prototypeObject的实例对象。因此这里就引申出了一个有意思的鸡和蛋的问题:前端

Object instanceof Function  // true
Function instanceof Object  // true

Object.__proto__ === Function.prototype  // true
Function.__proto__ === Function.prototype  // true
Function.prototype.__proto__ === Object.prototype  // true
复制代码

那么ObjectFunction,谁是鸡谁是蛋呢?java

接下来就来深刻探究下上面这段代码所引发的鸡生蛋蛋生鸡问题,从下面这张原型/原型链经典图入手,在这个过程当中深刻了解 Object.prototypeFunction.prototypefunction Object()function Function() 之间的关系,这个过程可能有点烧脑,毕竟是JS的一大玄学嘛。git

Object.prototype

原型链的尽头就是Object.prototype(不考虑 null 的状况下)。全部对象均从Object.prototype继承toString() 等公共属性github

Object.prototype 表示 Object 的原型对象,实际上Object.prototype 并非经过Object函数建立的,为何呢?看以下代码:浏览器

function Dog() {
  this.name = '川普';
}
var dog = new Dog();
dog.__proto__ === Dog.prototype;  // true
复制代码

实例对象的__proto__会指向构造函数的prototype,即dog.__proto__指向 Dog.prototype,可是Object.prototype.__proto__又是 null,因此 Object.prototype 并非经过 Object 函数建立的,那它如何生成的?其实 Object.prototype 是浏览器底层根据 ECMAScript 规范创造的一个对象,因此在经典图里面只是看起来Object.prototype 是经过 Object 函数建立的,实际上并非。函数

Function.prototype

Function.prototypeFunction.__proto__同一对象ui

这也意味着:Object/Array等等构造函数本质上和Function同样,均继承于Function.prototype,从经典图上来看都是经过new Function构造出来的this

固然,Function.prototype 对象是一个函数(对象),其__proto__属性指向 Object.prototype,即Function.prototype会直接继承root(Object.prototype)。spa

经过这点咱们能够弄清继承的原型链Function|Object|Array...--->Function.prototype--->Object.prototype(root)。以下图所示:

function Object()

Object 做为构造函数时,其__proto__属性指向 Function.prototype,即:

Object.__proto__ === Function.prototype  // true
复制代码

从经典图来看:

使用 new Object() 建立实例对象o1时,实例对象o1的 __proto__属性指向构造函数的 prototype 属性,对应上图就是 Object.prototype,即o1.__proto__ === Object.prototype结果为true

Function.prototype指向的对象,它的__proto__会指向Object.prototype,由于Function.prototype指向的对象也是一个普通的被Object建立的对象,因此也遵循基本的规则。

function Function()

Function也是一个函数对象,也有__proto__属性,既然是函数,那么它必定是被Function建立,因此Function是被自身建立的,因此它的__proto__指向了自身的Prototype

Function.__proto__ === Function.prototype  // true
复制代码

到这里就有点烧脑了吧,咱们再看下鸡生蛋蛋生鸡问题。

Function & Object 鸡和蛋问题

由上面可知,Object构造函数继承了Function.prototype,同时Function构造函数继承了Object.prototype,这里就产生了鸡和蛋的问题。为何会出现这种问题呢?必须首先更深刻一层去理解Function.prototype这个对象,由于它是致使Function instanceof ObjectObject instanceof Function都为true的缘由。

// Object instanceof Function 即
Object.__proto__ === Function.prototype   // true

// Function instanceof Object 即
Function.__proto__.__proto__ === Object.prototype   // true

// Object instanceof Object 即 
Object.__proto__.__proto__ === Object.prototype   // true

// Function instanceof Function 即 
Function.__proto__ === Function.prototype   // true
复制代码

根据JS规范,Function.prototype又是个不一样于通常函数(对象)的函数(对象),其中:

  1. Function.prototype像普通函数同样能够调用,但老是返回undefined
  2. 普通函数其实是Function的实例,即普通函数继承于Function.prototype。即func.__proto__ === Function.prototype
  3. Function.prototype继承于Object.prototype,而且没有prototype这个属性。
  4. 因此,Function.prototype实际上是个另类的函数,能够独立于/先于Function产生。

Object自己是个(构造)函数,是Function的实例,即Object.__proto__就是Function.prototype

总结:先有Object.prototype(原型链顶端),Function.prototype继承Object.prototype而产生,最后,FunctionObject和其它构造函数继承Function.prototype而产生

看到这里估计也都看烦了,是否是仍是有点混乱呀?乱也很正常。那这篇文章就先让它乱着,下一篇咱们将请另外一个老朋友来帮忙,把它完全理清楚,这位老朋友就是——instanceof,那就且听请下回分解咯。

若是以为文章对你有些许帮助,欢迎在个人GitHub博客点赞和关注,感激涕零!

相关文章
相关标签/搜索