做为一名前端开发者,咱们都知道JS是单继承的,而Object.prototype是原型链的顶端,全部对象从它继承了包括toString()、valueOf()等等公共属性。javascript
首先Object
和Function
都是构造函数,而全部的构造函数都是Function
的实例对象。 所以Object
是Function
的实例对象;而Function.prototype
是Object
的实例对象。因此这里就引申出了一个有意思的鸡和蛋的问题:前端
Object instanceof Function // true
Function instanceof Object // true
Object.__proto__ === Function.prototype // true
Function.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype // true
复制代码
那么Object
和Function
,谁是鸡谁是蛋呢?java
接下来就来深刻探究下上面这段代码所引发的鸡生蛋蛋生鸡问题,从下面这张原型/原型链经典图入手,在这个过程当中深刻了解 Object.prototype
、Function.prototype
、function Object()
、function Function()
之间的关系,这个过程可能有点烧脑,毕竟是JS的一大玄学嘛。git
原型链的尽头就是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.__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)
。以下图所示:
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
也是一个函数对象,也有__proto__
属性,既然是函数,那么它必定是被Function
建立,因此Function
是被自身建立的,因此它的__proto__
指向了自身的Prototype
:
Function.__proto__ === Function.prototype // true
复制代码
到这里就有点烧脑了吧,咱们再看下鸡生蛋蛋生鸡问题。
由上面可知,Object
构造函数继承了Function.prototype
,同时Function
构造函数继承了Object.prototype
,这里就产生了鸡和蛋的问题。为何会出现这种问题呢?必须首先更深刻一层去理解Function.prototype
这个对象,由于它是致使Function instanceof Object
和Object 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
又是个不一样于通常函数(对象)的函数(对象),其中:
Function.prototype
像普通函数同样能够调用,但老是返回undefined
。Function
的实例,即普通函数继承于Function.prototype
。即func.__proto__ === Function.prototype
。Function.prototype
继承于Object.prototype
,而且没有prototype
这个属性。Function.prototype
实际上是个另类的函数,能够独立于/先于Function
产生。而Object
自己是个(构造)函数,是Function
的实例,即Object.__proto__
就是Function.prototype
。
总结:先有Object.prototype
(原型链顶端),Function.prototype
继承Object.prototype
而产生,最后,Function
和Object
和其它构造函数继承Function.prototype
而产生。
看到这里估计也都看烦了,是否是仍是有点混乱呀?乱也很正常。那这篇文章就先让它乱着,下一篇咱们将请另外一个老朋友来帮忙,把它完全理清楚,这位老朋友就是——instanceof
,那就且听请下回分解咯。
若是以为文章对你有些许帮助,欢迎在个人GitHub博客点赞和关注,感激涕零!