introduction
This article delve into the next Function.__proto__ === Function.prototype
chicken-egg problem caused by the chicken, and in-depth understanding of the process Object.prototype
. Function.prototype
. function Object
. function Function
The relationship between.
Object.prototype
Object.prototype
It represents Object
the prototype object, which [[Prototype]]
properties are null
, access attributes __proto__
exposed interior of an object [[Prototype]]
. Object.prototype
Not through Object
function to create, and why? See the following code
function Foo() {
this.value = "foo";
}
let f = new Foo();
f.__proto__ === Foo.prototype;
// true
Instance of an object __proto__
prototype points to the constructor that f.__proto__
point Foo.prototype
, but Object.prototype.__proto__
is null
so Object.prototype
not through Object
functions created, how it was produced? In fact, Object.prototype
is based on the underlying object browser ECMAScript specification creation.
Object.prototype
Is the top prototype chain (without considering the null case), all objects inherit its toString
methods and properties.
Function.prototype
Function.prototype
It is a function of the object (object), which [[Prototype]]
internal property points built-in objects Object.prototype
. Function.prototype
The object itself no valueOf
property, from which Object.prototype
inherits the object valueOf
attributes.
Function.prototype
的 [[Class]]
属性是 Function
,所以这是一个函数,但又不大一样。为什么这么说呢?因为我们知道只有函数才有 prototype
属性,但并不是所有函数都有这个属性,因为 Function.prototype
这个函数就没有。
Function.prototype;
// ƒ () { [native code] }
Function.prototype.prototype;
// undefined
当然你会发现下面这个函数也没有 prototype 属性。
let fun = Function.prototype.bind();
// ƒ () { [native code] }
fun.prototype;
// undefined
为什么没有呢,我的理解是 Function.prototype
是引擎创建出来的函数,引擎认为不需要给这个函数对象添加 prototype
属性,不然 Function.prototype.prototype… 将无休无止并且没有存在的意义。
function Object
Object
作为构造函数时,其 [[Prototype]]
内部属性值指向 Function.prototype
,即
Object.__proto__ === Function.prototype;
// true
使用new Object()
创建新对象时,这个新对象的 [[Prototype]]
内部属性指向构造函数的 prototype
属性,对应上图就是 Object.prototype
。
当然也可以通过对象字面量等方式创建对象。
-
使用对象字面量创建的对象,其
[[Prototype]]
值是Object.prototype
。 -
使用数组字面量创建的对象,其
[[Prototype]]
值是Array.prototype
。 -
使用
function f(){}
函数创建的对象,其[[Prototype]]
值是Function.prototype
。 -
使用
new fun()
创建的对象,其中 fun 是由 JavaScript 提供的内建构造器函数之一(Object, Function, Array, Boolean, Date, Number, String 等等),其[[Prototype]]
值是fun.prototype
。 -
使用其他 JavaScript 构造器函数创建的对象,其
[[Prototype]]
值就是该构造器函数的prototype
属性。
let o = { a: 1 };
// 原型链: o ---> Object.prototype ---> null
let a = ["yo", "whadup", "?"];
// 原型链: a ---> Array.prototype ---> Object.prototype ---> null
function f() {
return 2;
}
// 原型链: f ---> Function.prototype ---> Object.prototype ---> null
var fun = new Function();
// 原型链: fun ---> Function.prototype ---> Object.prototype ---> null
function Foo() {
return {};
}
let foo = new Foo();
// 原型链: foo ---> Foo.prototype ---> Object.prototype ---> null
function Function
Function
构造函数是一个函数对象,其 [[Class]]
属性是 Function
。Function
的 [[Prototype]]
属性指向了 Function.prototype
,即
Function.__proto__ === Function.prototype;
// true
Function & Object 鸡蛋问题
我们看下面这段代码
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
。
// 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 种解释,争论点在于 Function
对象是不是由 Function
构造函数创建的一个实例?
解释 1. YES:按照 JavaScript 中“实例”的定义,a 是 b 的实例即 a instanceof b
为 true,默认判断条件就是 b.prototype
在 a 的原型链上。而 Function instanceof Function
为 true,本质上即 Object.getPrototypeOf(Function) === Function.prototype
,正符合此定义。
解释 2. NO: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 环境时都发生了什么?
-
用 C/C++ 构造内部数据结构创建一个 OP 即 (Object.prototype) 以及初始化其内部属性但不包括行为。
-
用 C/C++ 构造内部数据结构创建一个 FP 即 (Function.prototype) 以及初始化其内部属性但不包括行为。
-
将 FP 的 [[Prototype]] 指向 OP。
-
用 C/C++ 构造内部数据结构创建各种内置引用类型。
-
将各内置引用类型的[[Prototype]]指向 FP。
-
将 Function 的 prototype 指向 FP。
-
将 Object 的 prototype 指向 OP。
-
用 Function 实例化出 OP,FP,以及 Object 的行为并挂载。
-
用 Object 实例化出除 Object 以及 Function 的其他内置引用类型的 prototype 属性对象。
-
用 Function 实例化出除Object 以及 Function 的其他内置引用类型的 prototype 属性对象的行为并挂载。
-
实例化内置对象 Math 以及 Grobal
至此,所有内置类型构建完成。
原文:大专栏 深入探究 Function & Object 鸡蛋问题 - 黄庆的博客