Fork me on GitHub

深入探究Function与Object

令人费解的:Function.proto === Function.prototype

why?解释这个现象,需要先深入了解 Object.prototype、Function.prototype、function Object 、function Function 之间的关系。

Object.prototype

ECMAScript 上的定义:
The value of the [[Prototype]] internal property of the Object prototype object is null, the value of the [[Class]] internal property is “Object”, and the initial value of the [[Extensible]] internal property is true.

Object.prototype 表示 Object 的原型对象,其 [[Prototype]] 属性是 null。
访问器属性 proto 暴露了一个对象的内部 [[Prototype]] 。
Object.prototype 并不是通过 Object 函数创建的,为什么?

1
2
3
4
5
6
function Foo() {
this.value = 'foo';
}
let f = new Foo();
f.__proto__ === Foo.prototype;
// true

实例对象的 proto 指向构造函数的 prototype,即 f. proto 指向 Foo.prototype,但是 Object.prototype. proto === null,所以 Object.prototype 并不是通过 Object 函数创建的,那它如何生成的?

Object.prototype 是浏览器底层根据 ECMAScript 规范创造的一个对象。

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

Function.prototype

ECMAScript 上的定义:
The Function prototype object is itself a Function object (its [[Class]] is “Function”).
The value of the [[Prototype]] internal property of the Function prototype object is the standard built-in Object prototype object.
The Function prototype object does not have a valueOf property of its own; however, it inherits the valueOf property from the Object prototype Object.

Function.prototype 对象是一个函数(对象),其 [[Prototype]] 内部属性值指向内建对象 Object.prototype。

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

Function.prototype 对象自身没有 valueOf 属性,其从 Object.prototype 对象继承了valueOf 属性。

Function.prototype 的 [[Class]] 属性是 Function,所以这是一个函数,但又不大一样。为什么这么说呢?

因为我们知道只有函数才有 prototype 属性,但并不是所有函数都有这个属性,因为 Function.prototype 这个函数就没有。

1
2
3
4
5
6
7
8
9
10
11
Function.prototype
// ƒ () { [native code] }

Function.prototype.prototype
// undefined

let fun = Function.prototype.bind()
// ƒ () { [native code] }

fun.prototype
// undefined

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

function Object

ECMAScript定义:
The value of the [[Prototype]] internal property of the Object constructor is the standard built-in Function prototype object.

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

1
2
3
4
5
6
7
// Object created by new Function
* Object.__proto__ === Function.prototype // true

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

Object.prototype.__proto__ === null // true
Object.prototype.constructor === Object // true

通过对象字面量的方式创建对象:

1
2
3
let o = {a: 1};

o.__proto__ === Object.prototype

通过数组字面量创建对象:

1
2
3
4
let a = ["yo", "whadup", "?"];

a.__proto__ === Array.prototype // true
Array.prototype.__proto__ === Object.prototype // true

使用function() {}函数创建对象:

1
2
3
function fn () {}

fn.__proto__ === Function.prototype

使用new Function(),即由 JavaScript 提供的内建构造器函数之一(Object, Function, Array, Boolean, Date, Number, String 等等)创建对象:

1
2
3
4
5
let fun = new Function()
fun.__proto__ === Function.prototype

let bool = new Boolean()
bool.__proto__ === Boolean.prototype

使用JavaScript构造器函数创建对象:

1
2
3
function test() {}
let t = new test()
t.__proto__ === test.prototype

function Function

ECMAScript定义:
The Function constructor is itself a Function object and its [[Class]] is “Function”. The value of the [[Prototype]] internal property of the Function constructor is the standard built-in Function prototype object.

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

1
Function.__proto__ === Function.prototype

Function & Object 什么情况???

诡异的事实及原因分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.Object instanceof Function // true
// 原因:Object.__proto__===Function.prototype

2.Function instanceof Object // true
// 原因:Function.__proto__ === Function.prototype,Function.prototype.__proto__ === Object.prototype,
Function.__proto__.__proto__ === Object.prototype

3.Object instanceof Object
// 原因:Object.__proto__ === Function.prototype,
Function.prototype.__proto__ === Object.prototype,
Object.__proto__.__proto__ === Object.prototype

4.Function instanceof Function
// 原因:Function.__proto__ === Function.prototype

⚠️为什么Function.proto === Function.prototype?
也就是说Function 对象是不是由 Function 构造函数创建的一个实例?

  • 解释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’) )才有。

我也觉得第二种说法比较合理,即先有 Function.prototype 然后有的 function Function() ,所以就不存在鸡生蛋蛋生鸡问题了,把 Function.proto 指向 Function.prototype 是为了保证原型链的完整,让 Function 可以获取定义在 Object.prototype 上的方法。

终极关系图:

内置类型构建过程

JavaScript 内置类型是浏览器内核自带的,浏览器底层对 JavaScript 的实现基于 C/C++,那么浏览器在初始化 JavaScript 环境时都发生了什么?

  1. 用 C/C++ 构造内部数据结构创建一个 OP 即 (Object.prototype) 以及初始化其内部属性但不包括行为。
  2. 用 C/C++ 构造内部数据结构创建一个 FP 即 (Function.prototype) 以及初始化其内部属性但不包括行为。
  3. 将 FP 的 [[Prototype]] 指向 OP。
  4. 用 C/C++ 构造内部数据结构创建各种内置引用类型。
  5. 将各内置引用类型的[[Prototype]]指向 FP。
  6. 将 Function 的 prototype 指向 FP。
  7. 将 Object 的 prototype 指向 OP。
  8. 用 Function 实例化出 OP,FP,以及 Object 的行为并挂载。
  9. 用 Object 实例化出除 Object 以及 Function 的其他内置引用类型的 prototype 属性对象。
  10. 用 Function 实例化出除Object 以及 Function 的其他内置引用类型的 prototype 属性对象的行为并挂载。
  11. 实例化内置对象 Math 以及 Grobal

所有内置类型构建完成。

参考文章:
https://juejin.im/post/5cb4861ff265da036504efbc

本文标题:深入探究Function与Object

文章作者:tongtong

发布时间:2019年04月16日 - 20:04

最后更新:2019年04月17日 - 14:04

原始链接:https://ilove-coding.github.io/2019/04/16/1-3深入探究Function与Object/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

坚持原创技术分享,您的支持将鼓励我继续创作!
-------------本文结束-------------