-
Notifications
You must be signed in to change notification settings - Fork 840
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
从探究Function.__proto__===Function.prototype过程中的一些收获 #13
Comments
其实深究这种问题开发没多大用处,但是探寻事物的本质却收获不少。 |
了解了本质,开发的时候很多问题才能解决得更加灵活、优雅。 |
之前一直以为prototype属性一定是对象,直到发现了有Function.prototype这个东西。实际上呢,这句话‘Function对象是由Function构造函数创建的一个实例’,为了记住原型链里面的关系,按照这句话来记得话是没有毛病的,但是深究Function是一个内置对象也是没有毛病的。我是看见ES6的class的继承回过头来看这里的,因为ES6,里边的一个继承 |
我觉的你最后提的4个问题,我也是想知道具体为啥如此,不过以下是我的个人理解,可能有误: |
|
@jawil @Ghohankawk 这四个问题问得很深奥,啊不,很有深度(手动滑稽) |
|
我是認為 js runtime 中物件就是有一個 這些都只是包裝。 唯一特例是 Function , 關於 es6 新增的箭頭函數、generator 、 async function , 而 generator 與 async 就有趣了, 這二個建構式也都和 Function 一樣能用來動態建構函數, 但又一點很吊詭, GeneratorFunction 與 AsyncFunction 後來我發現這可能是 es6 class 的緣故。
目前想到的二個原因:
所以 GeneratorFunction 與 AsyncFunction 在內部 結論我認為 js 中的函數與物件都是一個黑箱, 而函數又比物件更黑,
但函數的閉包、this 、yield await 都是透過黑魔法實現的功能, 今年早些做了點有趣的功能,像 自己實現 Promise (結論是 async 可以透過 generator 實現,promise 可以以原生物件方式實現; 昨天才看到這篇,覺得也是另一種探討方向, |
|
偶然在控制台输入 |
@DOTA2mm |
你好你好~ 😃 |
加个好友啊?老年刀狗 |
👌 |
|
Function.prototype() |
所以这就是为什么Javascript是个蛋疼和优雅的东西,各种意义不清的东西,却能强行解释到一起 |
我的理解是这样:
Object 和 Function 的原型是两条线:
它们之间没有形成闭环回路,而是一种类似互相继承。因为互相继承,Function 和 Object 就可以共享对方的原型方法。 |
你好 |
也有此疑问,既然 |
|
你好,你的来件已收到。
|
我是黄海川。你的邮件我已经收到,谢谢!
|
在引出下面要阐述的问题答案之前,先深入了解几个重要慨念,之前这些概念也是模模糊糊,从最原始的一步步搞清楚。
什么是函数(function)?
解释定义最好的地方就是它的起源,这里便是ECMAScript规范,我们看看规范怎么定义函数(function)的。
摘录来自ECMAScript 5.1规范的4.3.24小节:
至于什么是实例对象,什么构造器(构造函数)下面的会详细讲,这里我们只引用定义,知道有这么个东西它叫这个名字就够了。
函数使用function 关键字来定义,其后跟随,函数名称标识符、 一对圆括号、一对花括号。
结合一个栗子理解这句话:
上面这几行代码就是一个函数,这个函数是标准内置构造器
Function
的一个实例,因此函数是一个对象。demo
就是这个函数的名字,对象是保存在内存中的,函数名demo
则是指向这个对象的指针。console.log('jawil')
则是可执行代码。对于内存,引用,指针不太明白,没有任何认知的童鞋可以去尝试搜索补习一下这些概念,其实都是一些概念,花点时间理解一下就好了。
在浏览器我们也可以检验一下:
上面只是创建函数的一种方式, JavaScript 中有三种创建形式,分别是:
①声明式
②函数的字面量或叫直接量或称表达式
③以new 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关键字到底是干什么的?
JS 的 new 到底是干什么的?
什么是构造函数?
我们看看ECMAScript规范怎么定义构造函数(constructor)的。
摘录来自ECMAScript 5.1规范的4.3.4小节:
构造函数就是初始化一个实例对象,对象的
prototype
属性是继承一个实例对象。这些抽象的东西其实不好讲,不好写,讲一个抽象的概念,又引出好几个抽象的概念,情何以堪,实例对象和原型prototype下一节讲,了解概念尽量多结合栗子加深理解,理解构造函数,首先就要理解上面函数的一个概念和定义。
这种抽象的东西不是很好记忆,我们通过一个示例来说明可能更好了解。
在javascript中,你可以把上面的代码看做一个函数,一个类,一个方法,都没有问题。
其实,在JavaScript中,首先,它是函数,任何一个函数你都可以把它看做是构造函数,它没有明显的特征。那什么时候它就明显了呢?实例化的时候。
当这一句代码结束,你就可以肯定的认为 Person 函数是一个构造函数,因为它 new 了"微醺岁月"。
那么,"微醺岁月" 是什么?"微醺岁月"是一个人,一个实实在在的人,是被构造函数初始化出来的。所以 var jawil 就变成了一个实例。
什么是实例对象,什么是原型对象?
原型
我们看看ECMAScript规范怎么定义构造函数(constructor)的。
摘录来自ECMAScript 5.1规范的4.3.5小节:
首先说一下,只有函数才有prototype(原型)属性。为什么只有函数才有prototype属性?ECMAScript规范就这么定的。
但是不是所有的函数都有prototype属性呢?答案是否定的,这可不一定。我们看个简单的栗子:
用 Function.prototype.bind 创建的函数对象没有 prototype 属性。
那么prototype(原型)到底有啥作用呢?
这些概念简单了解一下,这不是本人要讲的重点,这里一笔带过,不太懂的可以自己去查相关资料补习一下基础。
__proto__
引用《JavaScript权威指南》的一段描述:
翻译出来就是每个JS对象一定对应一个原型对象,并从原型对象继承属性和方法。好啦,既然有这么一个原型对象,那么对象怎么和它对应的?
对象__proto__属性的值就是它所对应的原型对象:
上面的代码应该已经足够解释清楚
__proto__
了。实例对象
把实例和对象对比来看,或许更容易理解。
实例对象和对象的区别,从定义上来讲:
实例是相对而言,这话怎么理解了,我们看下面两个小栗子比如说:
我们可以说a是Array数组的一个实例;
我们知道Array也是一个函数,虽然他是一个构造函数,只要是函数,从上面的知识点可以知道,Array是Function的一个实例。
通俗的理解这几个的关系:
问题引出
我们知道,Array,Date,Number,String,Boolean,Error甚至Object都是Function的一个实例,那么Function是谁的实例呢?
先看一个简单的小栗子:
再来看看这个:Function
也就是浏览器显示的这个,我们暂且这么类比:
我们再来看看,先暂时忽略后面的:
Person.__proto__=== Function.prototype;
//truePerson函数是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
是对象吗?当然是。
这是object的定义,
Object.prototype
显然是符合这个定义的。但是,Object.prototype并不是Object的实例。 这也很好理解Object.prototype.__proto__
是null。就如同刚才上面区分实例和对象一样,实例都是对象,而对象(比如说Object.prototype)不全是实例。
这已经某种程度上解开了鸡和蛋的问题:Object.prototype是对象,但它不是通过Object函数创建的。Object.prototype谁创建的,它是v8引擎(假设用的都是chrome浏览器)按照ECMAScript规范创造的一个对象。我只能这么给你解释。
未完待续,好累,歇一会儿~
关于这个问题也困扰了我很久,功力不够,无法详细回答,但是经过一番查找和探究,在知乎上看到了这篇回答,引用一下,与大家共同学习。
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 而产生。
参考文章
JavaScript 的语言设计有哪些缺陷?
JS 的 new 到底是干什么的?
从__proto__和prototype来深入理解JS对象和原型链
在JavaScript中,Function构造函数本身也算是Function类型的实例吗?
JS中先有Object还是先有Function?
JavaScript 世界万物诞生记
The text was updated successfully, but these errors were encountered: