Function&Object原型

      深入探究下 Function.proto === Function.prototype 引起的鸡生蛋蛋生鸡问题,并在这个过程中深入了解 Object.prototype、Function.prototype、function Object 、function Function 之间的关系。

Object.prototype

      Object.prototype表示 Object 的原型对象,其 Object.prototype.__proto__ 是 null ,因此 Object.prototype 并不是通过 Object 函数创建的。其实 Object.prototype 是浏览器底层根据 ECMAScript 规范创造的一个对象。

      Object.prototype 就是原型链的顶端(不考虑 null 的情况下),所有对象继承了它的 toString 等方法和属性。
iamge

Function.prototype

      Function.prototype 对象是一个函数(对象),其 [[Prototype]] 内部属性值指向内建对象 Object.prototype。Function.prototype 对象自身没有 valueOf 属性,其从 Object.prototype 对象继承了valueOf 属性。

image

      Function.prototype 的 [[Class]] 属性是 Function,所以这是一个函数,但又不大一样。为什么这么说呢?因为我们知道只有函数才有 prototype 属性,但并不是所有函数都有这个属性,因为 Function.prototype 这个函数就没有。

1
2
3
4
5
6
7
8
9
10
Function.prototype


Function.prototype.prototype
// undefined
let fun = Function.prototype.bind()


fun.prototype
// undefined

我的理解是 Function.prototype 是引擎创建出来的函数,引擎认为不需要给这个函数对象添加 prototype 属性,不然 Function.prototype.prototype… 将无休无止并且没有存在的意义。

function Object

      Object 作为构造函数时,其 [[Prototype]] 内部属性值指向 Function.prototype,即

1
2
Object.__proto__ === Function.prototype
// true

image

使用 new Object() 创建新对象时,这个新对象的 [[Prototype]] 内部属性指向构造函数的 prototype 属性,对应上图就是 Object.prototype。
当然也可以通过对象字面量等方式创建对象。

  • 使用对象字面量创建的对象,其 [[Prototype]] 值是 Object.prototype。
  • 使用数组字面量创建的对象,其 [[Prototype]] 值是 Array.prototype。
  • 使用 function f(){} 函数创建的对象,其 [[Prototype]] 值是 Function.prototype
  • 使用其他 JavaScript 构造器函数创建的对象,其 [[Prototype]] 值就是该构造器函数的 prototype 属性。

function Function

      Function 构造函数是一个函数对象,其 [[Class]] 属性是 Function。Function 的 [[Prototype]] 属性指向了 Function.prototype,即

1
2
Function.__proto__ === Function.prototype
// true

Function & Object 鸡蛋问题

1
2
3
4
5
Object instanceof Function         // true
Function instanceof Object // true

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

Object 构造函数继承了 Function.prototype,同时 Function 构造函数继承了Object.prototype。这里就产生了 鸡和蛋 的问题。为什么会出现这种问题,因为 Function.prototype 和 Function.proto 都指向 Function.prototype。

1
2
3
4
5
6
7
8
9
10
11
// 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

对于 Function.proto === Function.prototype 这一现象有如下2种解释,

  1. 按照 JavaScript 中“实例”的定义,a 是 b 的实例即 a instanceof b 为 true,默认判断条件就是 b.prototype 在 a 的原型链上。而 Function instanceof Function 为 true,本质上即 Object.getPrototypeOf(Function) === Function.prototype,正符合此定义。

  2. Function 是 built-in 的对象,也就是并不存在“Function对象由Function构造函数创建”这样显然会造成鸡生蛋蛋生鸡的问题。实际上,当你直接写一个函数时(如 function f() {} 或 x => x),也不存在调用 Function 构造器,只有在显式调用 Function 构造器时(如 new Function(‘x’, ‘return x’) )才有。

最后一个完整的原型链图:
image