从探究Function.__proto__===Function.prototype过程中的一些收获
jawil opened this issue · comments
在引出下面要阐述的问题答案之前,先深入了解几个重要慨念,之前这些概念也是模模糊糊,从最原始的一步步搞清楚。
什么是函数(function)?
解释定义最好的地方就是它的起源,这里便是ECMAScript规范,我们看看规范怎么定义函数(function)的。
摘录来自ECMAScript 5.1规范的4.3.24小节:
对象类型的成员,标准内置构造器
Function
的一个实例,并且可做为子程序被调用。注: 函数除了拥有命名的属性,还包含可执行代码、状态,用来确定被调用时的行为。函数的代码不限于 ECMAScript。
至于什么是实例对象,什么构造器(构造函数)下面的会详细讲,这里我们只引用定义,知道有这么个东西它叫这个名字就够了。
函数使用function 关键字来定义,其后跟随,函数名称标识符、 一对圆括号、一对花括号。
结合一个栗子理解这句话:
function demo(){
console.log('jawil');
}
上面这几行代码就是一个函数,这个函数是标准内置构造器 Function
的一个实例,因此函数是一个对象。demo
就是这个函数的名字,对象是保存在内存中的,函数名demo
则是指向这个对象的指针。console.log('jawil')
则是可执行代码。
对于内存,引用,指针不太明白,没有任何认知的童鞋可以去尝试搜索补习一下这些概念,其实都是一些概念,花点时间理解一下就好了。
在浏览器我们也可以检验一下:
demo instanceof Function
//true
上面只是创建函数的一种方式, JavaScript 中有三种创建形式,分别是:
①声明式
function fn(){ }; //这种定义的方式,无论在哪儿定义,别处都可以调用 ;
②函数的字面量或叫直接量或称表达式
var fn=function () { }; //此时函数作为表达式存在,调用只能在定义的后面;
//解释一下表达式:凡是将数据和运算符等联系起来有值得式子就是表达式。
③以new Function 的形式
var fn = new Function (arg1 , arg2 ,arg3 ,…, argN , body)
/*Function 构造函数所有的参数都是字符串类型。除了最后一个参数, 其余的参数都作为生成函数的参数即形参。
这里可以没有参数。最后一个参数, 表示的是要创建函数的函数体。
使用Function构造器生成的Function对象是在函数创建时解析的。这比你使用函数声明或者函数表达式(function)
并在你的代码中调用更为低效,因为使用后者创建的函数是跟其他代码一起解析的。
*/
上面三种创建方式,第三种var fn = new Function (arg1 , arg2 ,arg3 ,…, argN , body)
是最直观的,
很容易就联想到fn instanceof Function
,fn
一眼就看出来就是Function
的实例,但是为什么JavaScript还要创造用function
来创建一个函数呢?
答案显而易见,用function创建一个函数更优雅,灵活,书写方便,浏览器看到function时候其实已经帮你做了new Function()这一步了,function和new Function()创建的函数都是Function的一个实例,只是方式不一样,其实本质都是一样。就如同创建一个对象一样,我们可以var obj=new Object()
,当然我们也可以var obj={}
;
我觉得function创建函数只是new Function()创建函数的一个语法糖,不对之处还望指出,反正我是这么理解的。
JavaScript函数的new关键字到底是干什么的?
什么是构造函数?
我们看看ECMAScript规范怎么定义构造函数(constructor)的。
创建和初始化对象的函数对象。
注:构造器的“prototype”属性值是一个原型对象,它用来实现继承和共享属性。
构造函数就是初始化一个实例对象,对象的prototype
属性是继承一个实例对象。
这些抽象的东西其实不好讲,不好写,讲一个抽象的概念,又引出好几个抽象的概念,情何以堪,实例对象和原型prototype下一节讲,了解概念尽量多结合栗子加深理解,理解构造函数,首先就要理解上面函数的一个概念和定义。
这种抽象的东西不是很好记忆,我们通过一个示例来说明可能更好了解。
function Person(name){
this.name=name;
}
在javascript中,你可以把上面的代码看做一个函数,一个类,一个方法,都没有问题。
其实,在JavaScript中,首先,它是函数,任何一个函数你都可以把它看做是构造函数,它没有明显的特征。那什么时候它就明显了呢?实例化的时候。
var jawil=new Person('微醺岁月');
当这一句代码结束,你就可以肯定的认为 Person 函数是一个构造函数,因为它 new 了"微醺岁月"。
那么,"微醺岁月" 是什么?"微醺岁月"是一个人,一个实实在在的人,是被构造函数初始化出来的。所以 var jawil 就变成了一个实例。
什么是实例对象,什么是原型对象?
原型
我们看看ECMAScript规范怎么定义构造函数(constructor)的。
为其他对象提供共享属性的对象。
当构造器创建一个对象,为了解决对象的属性引用,该对象会隐式引用构造器的“prototype”属性。通过程序表达式 constructor.prototype 可以引用到构造器的“prototype”属性,并且添加到对象原型里的属性,会通过继承与所有共享此原型的对象共享。另外,可使用 Object.create 内置函数,通过明确指定原型来创建一个新对象。
首先说一下,只有函数才有prototype(原型)属性。为什么只有函数才有prototype属性?ECMAScript规范就这么定的。
但是不是所有的函数都有prototype属性呢?答案是否定的,这可不一定。我们看个简单的栗子:
用 Function.prototype.bind 创建的函数对象没有 prototype 属性。
那么prototype(原型)到底有啥作用呢?
prototype对象是实现面向对象的一个重要机制。每个函数也是一个对象,它们对应的类就是Function,每个函数对象都具有一个子对象prototype。Prototype 表示了该函数的原型,prototype表示了一个类的属性的集合。当通过new来生成一个类的对象时,prototype对象的属性就会成为实例化对象的属性。
这些概念简单了解一下,这不是本人要讲的重点,这里一笔带过,不太懂的可以自己去查相关资料补习一下基础。
__proto__
引用《JavaScript权威指南》的一段描述:
Every JavaScript object has a second JavaScript object (or null ,
but this is rare) associated with it. This second object is known as a prototype, and the first object inherits properties from the prototype.
翻译出来就是每个JS对象一定对应一个原型对象,并从原型对象继承属性和方法。好啦,既然有这么一个原型对象,那么对象怎么和它对应的?
对象__proto__属性的值就是它所对应的原型对象:
var one = {x: 1};
var two = new Object();
one.__proto__ === Object.prototype // true
two.__proto__ === Object.prototype // true
one.toString === one.__proto__.toString // true
上面的代码应该已经足够解释清楚__proto__
了。
实例对象
把实例和对象对比来看,或许更容易理解。
实例对象和对象的区别,从定义上来讲:
1、实例是类的具象化产品,
2、而对象是一个具有多种属性的内容结构。
3、实例都是对象,而对象(比如说Object.prototype)不全是实例。
实例是相对而言,这话怎么理解了,我们看下面两个小栗子比如说:
var a=new Array();
a instanceof Array//true
我们可以说a是Array数组的一个实例;
function Array(){
[native code]
}
Array instanceof Function//true
我们知道Array也是一个函数,虽然他是一个构造函数,只要是函数,从上面的知识点可以知道,Array是Function的一个实例。
通俗的理解这几个的关系:
JavaScript引擎是个工厂。
最初,工厂做了一个最原始的产品原型。
这个原型叫Object.prototype,本质上就是一组无序key-value存储({})之后,工厂在Object.prototype的基础上,研发出了可以保存一段“指令”并“生产产品”的原型产品,叫函数。
起名为Function.prototype,本质上就是[Function: Empty](空函数)为了规模化生产,工厂在函数的基础上,生产出了两个构造器:
生产函数的构造器叫Function,生产kv存储的构造器叫Object。你在工厂定制了一个产品,工厂根据Object.prototype给你做了一个Foo.prototype。
然后工厂发现你定制的产品很不错。就在Function.prototype的基础上做了一个Foo的构造器,叫Foo。工厂在每个产品上打了个标签__proto__,以标明这个产品是从哪个原型生产的。
为原型打了个标签constructor,标明哪个构造器可以依照这个原型生产产品。
为构造器打了标签prototype,标明这个构造器可以从哪个原型生产产品。所以,我觉得先有Function还是Object,就看工厂先造谁了。其实先做哪个都无所谓。因为在你定制之前,他们都做好了。
问题引出
我们知道,Array,Date,Number,String,Boolean,Error甚至Object都是Function的一个实例,那么Function是谁的实例呢?
先看一个简单的小栗子:
function Person(){
...一些自定义的code
}
Person.__proto__ === Function.prototype;//true
Person.prototype instanceof Object;//true
再来看看这个:Function
也就是浏览器显示的这个,我们暂且这么类比:
function Person(){
...一些自定义的code
}
function Function(){
[native code]//系统帮我们写的code
}
我们再来看看,先暂时忽略后面的:
Person.__proto__=== Function.prototype;
//true
Person函数是Function的一个实例。
Function.__proto__=== Function.prototype;
//true
上面说了,Person函数是Function的一个实例,这没有争议,那么这行代码是否可以说Function函数对象是由Function构造函数创建的一个实例?
因为我们普遍的认知就是:实例对象(A)的__proto__属性指向它的构造函数(B)的原型对象(prototype)。
大白话就是:A(儿子)继承了B(父母)的一些特性(prototype)才有了A。所以问题就来了,当A===B的时候,该怎么理解了?这就是今天问题的引出了,下面就要探讨这个问题了。
再来看:
Person.__proto__=== Person.prototype;
//false
这个显而易见可以看出,Person函数不是由Person的实例,因为Person是Function的一个实例。
那么问题来了:
Function构造函数的prototype属性和__proto__属性都指向同一个原型,是否可以说Function对象是由Function构造函数创建的一个实例?
Function.prototype
和Function.__proto__
都指向Function.prototype
,这就是鸡和蛋的问题怎么出现的一样。
在这之前,我一直有个误解就是,认为所有对象就是Object的实例,现在想起来真是Too young,Too simple.
Object.prototype
是对象吗?
当然是。
An object is a collection of properties and has a single prototype object. The prototype may be the null value.
这是object的定义,Object.prototype
显然是符合这个定义的。但是,Object.prototype并不是Object的实例。 这也很好理解Object.prototype.__proto__
是null。
就如同刚才上面区分实例和对象一样,实例都是对象,而对象(比如说Object.prototype)不全是实例。
这已经某种程度上解开了鸡和蛋的问题:Object.prototype是对象,但它不是通过Object函数创建的。Object.prototype谁创建的,它是v8引擎(假设用的都是chrome浏览器)按照ECMAScript规范创造的一个对象。我只能这么给你解释。
未完待续,好累,歇一会儿~
关于这个问题也困扰了我很久,功力不够,无法详细回答,但是经过一番查找和探究,在知乎上看到了这篇回答,引用一下,与大家共同学习。
在JavaScript中,Function构造函数本身也算是Function类型的实例吗?Function构造函数的prototype属性和__proto__属性都指向同一个原型,是否可以说Function对象是由Function构造函数创建的一个实例?
Yes and No.
Yes 的部分:
按照JS中“实例”的定义,a 是 b 的实例即 a instanceof b
为 true,默认判断条件就是 b.prototype
在 a 的原型链上。而 Function instanceof Function
为 true,本质上即 Object.getPrototypeOf(Function) === Function.prototype
,正符合此定义。
No 的部分:
Function 是 built-in
的对象,也就是并不存在“Function对象由Function构造函数创建”这样显然会造成鸡生蛋蛋生鸡的问题。实际上,当你直接写一个函数时(如 function f() {}
或 x => x
),也不存在调用 Function 构造器,只有在你显式调用 Function 构造器时(如 new Function('x', 'return x')
)才有。
注意,本质上,a instanceof b
只是一个运算,即满足某种条件就返回 true/false,当我们说 a 是 b 的实例时,也只是表示他们符合某种关系。JS 是一门强大的动态语言,你甚至可以在运行时改变这种关系,比如修改对象的原型从而改变 instanceof 运算的结果。此外,ES6+ 已允许通过 Symbol.hasInstance
来自定义 instanceof 运算。
我知道很多 JS 学习者会迷恋于对象和函数之间的 instanceof 关系,并希望探究到底谁更本源?我当初也在这个问题上浪费了很多时间。但这是一个伪问题。参见:JavaScript 里 Function 也算一种基本类型?以上。
收获
对JavaScript的原型和原型链相比以前有了一个更深刻的认识,同时也对函数,构造函数,实例对象的一些概念有了一个更具体的认知,以前对这些概念都是模模糊糊,没有一个明确的概念,导致在理解一些问题上出现盲点,比如说:function和Function的问题,现在总是认知清楚了,也了解到没有十全十美的语言,任何语言也有它的一些缺陷和漏洞,比如说Function对象是由Function构造函数创建的一个实例?typeof null的返回值是Object的问题,历史的车轮滚滚向前,语言也是向前发展,但愿JavaScript发展越来越好,越来越完善,一统天下😄。
最后感觉还是有疑问,很纠结,越陷越深,慢慢回答自己的问题
结论:先有 Object.prototype(原型链顶端),Function.prototype 继承 Object.prototype 而产生,最后,Function 和 Object 和其它构造函数继承 Function.prototype 而产生。
- 先有 Object.prototype,再有 Object,那么先有 Object.prototype 里面的这个 Object 代表的是什么呢?
- Function.proto=== Function.prototype;
Function 构造函数的 prototype 属性和__proto__属性都指向同一个原型,是否可以说 Function 对象是由 Function 构造函数创建的一个实例?
- Object instanceof Function // true
Function instanceof Object // true
Object 本身是构造函数,继承了 Function.prototype;Function 也是对象,继承了 Object.prototype。感觉成了鸡和蛋的问题了。
- 比如说:
function Person(){}
Person.prototype 是一个对象,为什么 Function.prototype 却是一个函数呢,当然函数也是一个对象,为什么要这么设计呢?
参考文章
JavaScript 的语言设计有哪些缺陷?
JS 的 new 到底是干什么的?
从__proto__和prototype来深入理解JS对象和原型链
在JavaScript中,Function构造函数本身也算是Function类型的实例吗?
JS中先有Object还是先有Function?
JavaScript 世界万物诞生记
其实深究这种问题开发没多大用处,但是探寻事物的本质却收获不少。
了解了本质,开发的时候很多问题才能解决得更加灵活、优雅。
之前一直以为prototype属性一定是对象,直到发现了有Function.prototype这个东西。实际上呢,这句话‘Function对象是由Function构造函数创建的一个实例’,为了记住原型链里面的关系,按照这句话来记得话是没有毛病的,但是深究Function是一个内置对象也是没有毛病的。我是看见ES6的class的继承回过头来看这里的,因为ES6,里边的一个继承 B.__proto__= A
,这里不符合我之前所理解的所有的prototype都是对象这一个理论。纠结了好几天。还有,Object.prototype中的Object到底是哪来的,这个问题我发现也被绕进去了。
我觉的你最后提的4个问题,我也是想知道具体为啥如此,不过以下是我的个人理解,可能有误:
第一个是说Object,这个名词,可能就是你说的v8引擎创建的默认对象,而把它起名为了object
第二个,好像就应该说,为啥说,函数就是对象,等号左边是,Function这个对象,而右边是Function这个函数,同名函数和对象
第三个,就是如下:
Object.proto==Function.prototype,因此,Object是Function的实例,
而Function.proto.proto==Object.prototype,Function是Object的实例
这刚好解释了,为啥,函数是一种特殊的对象,对象又是构造函数产生的,这种死循环
第四个,为啥这么设计我,也不太明白,可能是,其他的都是对象,那么怎么区分函数和对象?因为不说第三条吗?函数就是对象,对象即是函数,要细分的时候,总的有分区吧,
比如,我们一般认为Object,就是个对象,不说函数,而Function默认都是认为函数,不说是对象
Function.__proto__ === Function.prototype
,很简单的,函数是Function的实例,每一个实例内部都有一个属性__proto__指向该构造函数的prototype,恰巧Function本身就一个函数 function Function() {}
@jawil @Ghohankawk 这四个问题问得很深奥,啊不,很有深度(手动滑稽)
1、天知道Object.prototype的Object到底指代什么
2、Function.proto===Function.prototype成立。既是也不是。
是:从原型链上看,Function对象的prototype是在Function构造函数的原型链上的,实例的说法成立。
不是:Function是内建对象,如果说Function对象是Function构造函数创建,那Function构造函数又是谁创建的呢?
3、先有Object.prototype(原型链顶端),Function.prototype继承Object.prototype而产生,最后,Function和Object和其它构造函数继承Function.prototype而产生。详见:
creeperyang/blog#9
http://louiszhai.github.io/2015/12/17/prototype/
4、我觉得是为了更好地从字面意思上去区分,看到Object就知道是某个对象,看到Function就知道是某个函数,不然,看到Function,想到的是既是对象又是函数,那该如何去用?
Function.__proto__ === Function.prototype
,很简单的,函数是Function的实例,每一个实例内部都有一个属性__proto__指向该构造函数的prototype,恰巧Function本身就一个函数 function Function() {}
每一个实例内部都有一个属性__proto__指向该构造函数的prototype
let a = [];
a.__proto__ === Array.prototype
// true
Array.__proto__ === Function.prototype
// true
Array.prototype.__proto__ === Object.prototype // 实例 Array.prototype
// true
a.constructor === Array
// true
Array.constructor === Function
// true
Array.prototype.constructor === Array // 构造函数的prototype? --> Object
// true
我是認為 js runtime 中物件就是有一個 __proto__
屬性,
在查詢屬性時就會一路用 proto 往上找。
函數可以當作建構函數,只是方便我們建立同類的物件;
並在建構物件時,把 proto 指向建構式的 prototype 屬性。
這些都只是包裝。
Object 與 Object.prototype 沒什麼特殊意義,
他只是提供了一些物件常用的方法,
而那些方法其實都能自己 patch 出來。
所以你大可自己寫一個 MyObject 建構式,
在 MyObject.prototype 上也可以自幹出
多數 Object.prototype 提供的方法。
唯一特例是 Function ,
Function.prototype 不是物件,
而也是函數;我不確定這有什麼意義。
但函數也是一種物件,可以有擁有屬性與原型,
所以 Function.prototype.proto == Object.prototype 。
關於 es6 新增的箭頭函數、generator 、 async function ,
其中箭頭函數的原型也是指向 Function.prototype ,
和一般函數沒有差別。
而 generator 與 async 就有趣了,
他們的建構函數不是公開的全域變數,
要用 (function*(){}).constructor
與 (async function() {}).constructor
來獲取。
(以下稱為 GeneratorFunction 與 AsyncFunction 。)
這二個建構式也都和 Function 一樣能用來動態建構函數,
他們的實例的原型是各自建構子的 .prototype
,
*.prototype
的原型又指向 Function.prototype ,
所以 instanceof 可以得到正確的結果。
但又一點很吊詭, GeneratorFunction 與 AsyncFunction
原型不是指向 Function.prototype 。
原本 js 中所有函數包括建構函數的原型都是指向 Function.prototype ,
但 GeneratorFunction 與 AsyncFunction 的原型是指向 Function 。
GeneratorFunction.__proto__ == Function
。
後來我發現這可能是 es6 class 的緣故。
如果用 es6 class 語法繼承現有類別,
雖然子 constructor 仍是函數,
但 constructor.__proto__
會指向父建構式。
class SubObject extends Object {
}
SubObject.prototype instanceof Object.prototype // true
SubObject instanceof Object // true
SubObject.entries == Object.entries // true
目前想到的二個原因:
- 讓 instanceof 算符可以運作在 class 上,也就是建構函數上。
比較好看而已。 - 讓子類繼承父類的靜態方法。因為原型指向了父類,自然能從子類存取到父類的屬性。
所以 GeneratorFunction 與 AsyncFunction 在內部
應該是用類似 class extends Function
的方法實作的。
結論
我認為 js 中的函數與物件都是一個黑箱,
那些建構式只是其一個很有限的介面,
提供很少的方法讓我們接觸外部。
而函數又比物件更黑,
相比物件只是簡單的 key value 集合,
加上一個 __proto__
屬性。
基本上是可以自己實現的。
child.get = function (key) {
if (this.hasOwn(key)) return this.getOwn(key)
else if (this.parent) return this.parent.get(ket)
else return undefined // parent is null
但函數的閉包、this 、yield await 都是透過黑魔法實現的功能,
需要在執行時做很多手腳才能辦到,
不然就是像 babel 要完全重編譯成另一種樣子。
今年早些做了點有趣的功能,像 自己實現 Promise
與 用 generator 實現 async 函數 ,
所以研究了一下要怎麼為 generator function 加 method 但又不加到所有 function 上,
所以找到了 GeneratorFunction.prototype 這東西,
順便做了點實驗。
(結論是 async 可以透過 generator 實現,promise 可以以原生物件方式實現;
整個 async 與 promise 系列升級,只有 generator 是真正重要不可取代的元件。)
昨天才看到這篇,覺得也是另一種探討方向,
也想把自己的想法與發現寫下來,就寫了。
(發現 AsyncFunction.__proto__ != Function.prototype
。)
沒想到寫到一半忽然想通是 es6 class extends 的原因,
文章長度幾乎加倍……。
Function.__proto__ === Function.prototype
,很简单的,函数是Function的实例,每一个实例内部都有一个属性__proto__指向该构造函数的prototype,恰巧Function本身就一个函数 function Function() {}每一个实例内部都有一个属性__proto__指向该构造函数的prototype
let a = []; a.__proto__ === Array.prototype // true Array.__proto__ === Function.prototype // true Array.prototype.__proto__ === Object.prototype // 实例 Array.prototype // true a.constructor === Array // true Array.constructor === Function // true Array.prototype.constructor === Array // 构造函数的prototype? --> Object // true
// 1.构造函数创建实例。实例一创造出来就有constructor属性(指向构造函数)和__proto__属性(指向原型对象)
let a = [];
a.constructor === Array // true
a.__proto__ === Array.prototype // true
Array.constructor === Function // true
Array.__proto__ === Function.prototype // true
Function.constructor === Function // true
Function.__proto__ === Function.prototype // true
Object.constructor === Function // true
Object.__proto__ === Function.prototype // true
// 2.构造函数对应有原型对象,有constructor属性(指向构造函数)和__proto__属性(指向原型链上级)
Array.prototype.constructor === Array // true
Array.prototype.__proto__ === Object.prototype //true
Function.prototype.constructor === Function // true
Function.prototype.__proto__ === Object.prototype // true
Object.prototype.constructor === Object //true
Object.prototype.__proto__ === null // true
偶然在控制台输入 Function.prototype
发现是函数类型,然后找到了这篇文章。收获良多,感谢博主。
@DOTA2mm
其实Object
,String
,Number
等等都是构造函数,刀友你好
@DOTA2mm
其实Object
,String
,Number
等等都是构造函数,刀友你好
你好你好~ 😃
hezfblog 很赞!
@DOTA2mm
其实Object
,String
,Number
等等都是构造函数,刀友你好你好你好~ 😃
hezfblog 很赞!
加个好友啊?老年刀狗
130128931
@DOTA2mm
其实Object
,String
,Number
等等都是构造函数,刀友你好你好你好~ 😃
hezfblog 很赞!加个好友啊?老年刀狗
130128931
👌
Function.__proto__ === Function.prototype
导致 Function.constructor === Function
,即: Function 是它自己的构造函数
Function.prototype()
为什么可以直接执行 执行结果是什么?
typeof Function.prototype 结果是function
Function.prototype instanceof Function 结构false
所以这就是为什么Javascript是个蛋疼和优雅的东西,各种意义不清的东西,却能强行解释到一起
我的理解是这样:
- 普通对象的原型根源是
Object.prototype
,而Object.prototype
的最终根源是null
。 - 函数对象(Array、Number、Date、Object等等、包括 Function)它们的原型都继承于
Function.prototype
,同时Function
对象会从自己的原型上获得一些方法,比如apply
,call
,bind
等等。(具体的可以看MDN)。
Object 和 Function 的原型是两条线:
Function -> Function.prototype -> Object.prototype -> null
Object -> Function.prototype -> Object.prototype -> null
它们之间没有形成闭环回路,而是一种类似互相继承。因为互相继承,Function 和 Object 就可以共享对方的原型方法。
你好
也有此疑问,既然 Function instanceof Object === true
,为什么Function.__proto__ !== Object.prototype
?
也有此疑问,既然
Function instanceof Object === true
,为什么Function.__proto__ !== Object.prototype
?
Function.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype // true
个人理解:
模型:
模型解释:每个函数(是不是构造函数都可,除了箭头)都唯一对应一个原型对象,根据该函数创建的实例指向该原型对象。
设构造函数 Object 的原型对象是 A,构造函数 Function 的原型对象是 B.
规定:默认下,所有的函数的 原型对象 均指向 A。
此规定在原型链顶端存在唯一例外: 函数 Object 的 原型对象 指向 B.
这构成循环:
最后可以发现,这个完整的循环链从下往上,只有 Fucntion 函数没有画出它的__proto__指向谁。
这是因为,Function 函数是 Function 函数自身的实例。之所以这样设计:
我们假设 Function 是某个函数的实例,那它只能是 Fucntion 的实例了;
我们假设 Funciton 不是任何函数的实例:js 规定任何对象都存在__proto__,该假设不成立。