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

鸡和蛋问题的由来

首先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,谁是鸡谁是蛋呢?

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

Object.prototype

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

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__同一对象

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

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

通过这点我们可以弄清继承的原型链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博客点赞和关注,感激不尽!



JavaScript      JavaScript Function

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!