摘要:有個(gè)例外他就是??醋髠?cè)對象的原型鏈上是否有第一步得到。將各內(nèi)置引用類型的指向。用實(shí)例化出,,以及的行為并掛載。實(shí)例化內(nèi)置對象以及至此,所有內(nèi)置類型構(gòu)建完成。最后的最后,你還對是現(xiàn)有還是現(xiàn)有有想法了嗎以上均為個(gè)人查閱及實(shí)踐總結(jié)的觀點(diǎn)。
來個(gè)摸底測試,說出以下每個(gè)表達(dá)式的結(jié)果
function F(){}; var o = {}; typeof F; typeof o; typeof F.prototype; typeof o.prototype; typeof new F; typeof (new F).prototype; typeof (new F).__proto__; typeof F.__proto__; typeof o.__proto__; typeof Object; typeof Function; typeof (new Function).prototype; typeof (new Function).__proto__; typeof (new Object).prototype; typeof (new Object).__proto__; typeof Object.prototype; typeof Object.__proto__; typeof Function.prototype; typeof Function.__proto__;
function F(){}; var o = {}; typeof F; //==> function typeof o; //==> object typeof F.prototype; //==> object typeof o.prototype; //==> undefinded typeof new F; //==> object typeof (new F).prototype; //==> undefined typeof (new F).__proto__; //==> object typeof F.__proto__; //==> function typeof o.__proto__; //==> object typeof Object; //==> function typeof Function; //==> function typeof (new Function).prototype; //==> object typeof (new Function).__proto__; //==> function typeof (new Object).prototype; //==> undefined typeof (new Object).__proto__; //==> object typeof Object.prototype; //==> object typeof Object.__proto__; //==> function typeof Function.prototype; //==> function typeof Function.__proto__; //==> function
看到這里相信有不少入門不久的同學(xué)已經(jīng)產(chǎn)生疑惑了 是真的嗎 然后在瀏覽器試過一番發(fā)現(xiàn)真是如此。
解開疑惑之前先回顧些大家都知道的知識點(diǎn):
引用 MDN 關(guān)于 對象實(shí)例和對象原型對象 的闡述:
JavaScript語言的所有對象都是由Object衍生的對象;
所有對象都繼承了Object.prototype的方法和屬性,盡管它們可能被覆蓋。
例如,其它的構(gòu)造器原型覆蓋了constructor屬性并提供了其自己的toString方法。
原型對象的更改會傳播給所有的對象,除非這些屬性和方法在原型鏈中被再次覆蓋。
就如我們經(jīng)常在各類教科中看到的 所有的實(shí)例對象都是 Object 類型的實(shí)例
那么我們平時(shí)都是如何確定一個(gè)對象是否是另一個(gè)類型或?qū)ο蟮膶?shí)例的呢?
對我們可以使用 typeof 關(guān)鍵字 亦或可以使用關(guān)鍵字 instanceof 來確定某個(gè)對象是否是指定類型或?qū)ο蟮膶?shí)例:
typeof {} //object ({}) instanceof Object //true typeof Date //function Date instanceof Function //true typeof Date.prototype //obejct Date.prototype instanceof Object //true
然而針對 Object 的 prototype 屬性:
typeof Object.prototype //object Object.prototype instanceof Object // false
為什么,要想搞清楚為什么就得明白 instanceof 這個(gè)關(guān)鍵字在表達(dá)式中發(fā)生了什么?
在弄清楚 instanceof 之前 還得弄清楚一樣?xùn)|西 就是 new 一個(gè)對象到底做了什么:
如 var a = new A(); 認(rèn)為 “a為A函數(shù)的實(shí)例對象”
new操作的過程是什么? 可以總結(jié)如下:
1.new 創(chuàng)建一個(gè)空對象{}
2.然后將A.prototype的引用放置到該對象的原型鏈上。即a.__proto__指向 A.prototype
3.執(zhí)行A函數(shù),將A中this指向該對象,執(zhí)行結(jié)束,如果沒有return那么默認(rèn)返回this引用
那么new的其中一個(gè)的作用便是把A.prototype的指向添加到了a的原型鏈中。
至此我們便知道了如下關(guān)系:
a.__proto__ === A.prototype //true a instanceof A //true
故為何不得出一個(gè)結(jié)論:
instanceof 操作符其實(shí)就是檢查左側(cè)的元素的 __proto__鏈上有沒有右側(cè)類或?qū)ο蟮膒rototype存在。 同理 當(dāng)某某某是某某某的實(shí)例時(shí) 其實(shí)也是證明左側(cè)的__proto__鏈上有右側(cè)類或?qū)ο蟮膒rototype存在。
細(xì)節(jié)剖析如下:
1.看右側(cè)的 A 獲取其 prototype 得到 A.prototype。
2.看左側(cè) a 對象的原型鏈上是否有第一步得到 A.prototype。
1)獲取 a.__proto__對象看是否為A.prototype,是則返回 true
2)獲取 a.__proto__.__proto__ 對象看是否為A.prototype,是則返回 true
3)重復(fù)獲取左側(cè)的原型鏈上的[[Prototype]]特性即__proto__屬性進(jìn)行判斷直到為空返回 false。
校驗(yàn)真理,我們都知道 js 有幾大內(nèi)置類型 這些類型都是 Function 的實(shí)例,是 Function 類型:
out(typeof Date) //Function out(typeof RegExp) //Function out(typeof Number) //Function out(typeof Boolean) //Function out(typeof String) //Function out(typeof Array) //Function out(typeof Error) //Function //... out(Date.__proto__ === Function.prototype) //true out(RegExp.__proto__ === Function.prototype) //true out(Number.__proto__ === Function.prototype) //true out(Boolean.__proto__ === Function.prototype) //true out(String.__proto__ === Function.prototype) //true out(Array.__proto__ === Function.prototype) //true out(Error.__proto__ === Function.prototype) //true //... out(Object.getPrototypeOf(Date) === Function.prototype) //true out(Object.getPrototypeOf(RegExp) === Function.prototype) //true out(Object.getPrototypeOf(Number) === Function.prototype) //true out(Object.getPrototypeOf(Boolean) === Function.prototype) //true out(Object.getPrototypeOf(String) === Function.prototype) //true out(Object.getPrototypeOf(Array) === Function.prototype) //true out(Object.getPrototypeOf(Error) === Function.prototype) //true //... out( Date instanceof Function) //true out( RegExp instanceof Function) //true out( Number instanceof Function) //true out( Boolean instanceof Function) //true out( String instanceof Function) //true out( Array instanceof Function) //true out( Error instanceof Function) //true //...
回到上述針對 Object 的 prototype 屬性疑惑 為什么到了 Object 就得不出一樣的結(jié)果了呢?
我們都知道每個(gè)函數(shù)對象亦或函數(shù)類型都會有個(gè) prototype 屬性,在其上掛載的方法和屬性均能夠被該類型實(shí)例化出來的對象共享,因?yàn)閷?shí)例化出來的對象擁有 [[Prototype]]特性即 __proto__ 屬性,js 便是通過該特性實(shí)現(xiàn)原型鏈機(jī)制。
那么這些函數(shù)的 prototype 屬性對象是否也有自己的[[Prototype]]特性即 __proto__ 屬性呢?
out(typeof Date.prototype) //object out(typeof RegExp.prototype) //object out(typeof Number.prototype) //object out(typeof Boolean.prototype) //object out(typeof String.prototype) //object out(typeof Array.prototype) //object out(typeof Error.prototype) //object out(typeof Object.getPrototypeOf(Date.prototype)) //object out(typeof Object.getPrototypeOf(RegExp.prototype)) //object out(typeof Object.getPrototypeOf(Number.prototype)) //object out(typeof Object.getPrototypeOf(Boolean.prototype)) //object out(typeof Object.getPrototypeOf(String.prototype)) //object out(typeof Object.getPrototypeOf(Array.prototype)) //object out(typeof Object.getPrototypeOf(Error.prototype)) //object out(Object.getPrototypeOf(Date.prototype) === Object.prototype) //true out(Object.getPrototypeOf(RegExp.prototype) === Object.prototype) //true out(Object.getPrototypeOf(Number.prototype) === Object.prototype) //true out(Object.getPrototypeOf(Boolean.prototype) === Object.prototype) //true out(Object.getPrototypeOf(String.prototype) === Object.prototype) //true out(Object.getPrototypeOf(Array.prototype) === Object.prototype) //true out(Object.getPrototypeOf(Error.prototype) === Object.prototype) //true
可以看出每個(gè)函數(shù)對象的 prototype 屬性也有自己的[[Prototype]]特性 而且指向的是 Object.prototype
那么是否所有對象都會有直接的[[Prototype]]特性 呢?
out( Object.getPrototypeOf( Object.getPrototypeOf(Date.prototype))) //null out( Object.getPrototypeOf( Object.getPrototypeOf(RegExp.prototype))) //null out( Object.getPrototypeOf( Object.getPrototypeOf(Number.prototype))) //null out( Object.getPrototypeOf( Object.getPrototypeOf(Boolean.prototype))) //null out( Object.getPrototypeOf( Object.getPrototypeOf(String.prototype))) //null out( Object.getPrototypeOf( Object.getPrototypeOf(Array.prototype))) //null out( Object.getPrototypeOf( Object.getPrototypeOf(Error.prototype))) //null out( Object.getPrototypeOf( Object.prototype)) //null
答案是否。
有個(gè)例外他就是 Object.prototype。
回看前面的 Demo:
Object.prototype instanceof Object // false
從前面的代碼輸出我們看到 Object.prototype 對象是沒有[[Prototype]]特性的,同時(shí)前面我們也討論過 instanceof 這個(gè)關(guān)鍵字所涉及的具體操作。
我們可以具體剖析如下:
1.看右側(cè)的 Object 獲取其 prototype 得到 Object.prototype。
2.看左側(cè) Object.prototype 對象的原型鏈上是否有第一步得到 Object.prototype。
1)獲取 Object.prototype.__proto__對象為空直接返回 false。
那么為什么所有的對象都有[[Prototype]] 特性,唯獨(dú)Object.prototype沒有呢。答案很簡單:既然 JS的繼承機(jī)制是基于原型鏈的那總該有個(gè)頭吧,這個(gè)頭便是Object.prototype 。
再來一發(fā):
out( typeof Function) //function out( typeof Object) //function out( Object instanceof Function) //true out( Function instanceof Function) //true
在學(xué)習(xí) JS 的過程中我們已經(jīng)知道所有的數(shù)據(jù)類型都是 Function 類型的實(shí)例,包括 Object 在內(nèi),但是我們都知道所有的對象都是 Object 的實(shí)例,這時(shí)便引出文章的題目
到底是先有 Function 還是先有 Object?out( Function.__proto__ === Function.prototype) //true out( Object.__proto__ === Function.prototype) //true out( Object.getPrototypeOf(Function) === Function.prototype) //true out( Object.getPrototypeOf(Object) === Function.prototype) //true out( Object.getPrototypeOf(Function) === Function.prototype) //true out( Object.getPrototypeOf(Object) === Function.prototype) //true out( Object instanceof Function) //true out( Function instanceof Function) //true
從上述代碼加上前面得出的結(jié)論我們可以看出
Function 和 Object 的原型鏈上都有 Function.prototype
我們再來詳細(xì)看看 Function.prototype
out( typeof Function.prototype); // function out( Function.prototype instanceof Object) //true
這時(shí)候問題升華為
Function.prototype 和 Object.prototype 的關(guān)系。out( Function.prototype.__proto__ === Object.prototype)
這時(shí)候關(guān)系已經(jīng)很明了了:
我們都知道除了 Object.prototype 之外所有對象都會有[[Prototype]]特性 即 __proto__ 屬性,故 Function.prototype 也不例外,
Function.prototype 指向的是 Object.prototype
這時(shí)候就可以清楚的知道為什么說所有類型都是 Function 的實(shí)例,同時(shí)也是 Object 的實(shí)例:
因?yàn)樗械念愋偷?b>[[Prototype]]特性 即 __proto__ 屬性均指向的是 Function.prototype ,同時(shí) Function.prototype 的[[Prototype]]特性 即 __proto__ 屬性又指向了 Object.prototype 。
故大王是Object.prototype,二王是Function.prototype,其他均是小弟,但是小弟也有等級劃分
先接著來看 Function:
out( typeof Function.prototype); // function out( typeof Function.__proto__); // function out( Function.prototype === Function.__proto__);// true
首先我們可以看出 Function.prototype 和其他類型的 prototype 屬性是 object 類型不一樣, 是 function 類型
其次 Function.__proto__ 指向了 Function.prototype。
我們知道當(dāng)一個(gè)類型實(shí)例化出對象時(shí),這些對象的便會共享掛載在該類型的 prototype 屬性上的 資源,因?yàn)檫@些對象均有[[Prototype]]特性,指向的就是實(shí)例化出這些對象的類型的 prototype
從前面的例子可以看到所有的類型的[[Prototype]]特性均指向了 Function.prototype,所以這些類型都具有了使用掛載在Function.prototype上的資源的權(quán)利。因此可以看出,當(dāng)一個(gè)對象具有使用掛載在Function.prototype上的資源的權(quán)利時(shí),及該對象[[Prototype]]指向 Function.prototype 時(shí)代表這個(gè)對象是個(gè) Function 實(shí)例是一個(gè)類型,能夠?qū)嵗鲈擃愋偷膶ο?,?dāng)然包括 Function 在內(nèi)。
又因?yàn)樗蓄愋偷?b>[[Prototype]]指向 Function.prototype 而 Function.prototype 的[[Prototype]]指向是 Object.prototype,所以這些類型都具有使用掛載在 Object.prototype 上的資源的權(quán)利。
那用這些類型實(shí)例化出來的對象呢 類型的原型鏈并不在實(shí)例化出來的對象上呀,但是這些實(shí)例化出來的對象的[[Protitype]]指向的是其類型的 prototype 屬性
往回看前面的例子 可以看到有一段
out(Object.getPrototypeOf(Date.prototype) === Object.prototype) //true out(Object.getPrototypeOf(RegExp.prototype) === Object.prototype) //true out(Object.getPrototypeOf(Number.prototype) === Object.prototype) //true out(Object.getPrototypeOf(Boolean.prototype) === Object.prototype) //true out(Object.getPrototypeOf(String.prototype) === Object.prototype) //true out(Object.getPrototypeOf(Array.prototype) === Object.prototype) //true out(Object.getPrototypeOf(Error.prototype) === Object.prototype) //true out(Object.getPrototypeOf(Function.prototype) === Object.prototype) //true
可以看到這些類型的 prototype 屬性的[[Protitype]]指向的是 Object.prototype 故至此,所有對象包括類型對象亦或類型實(shí)例化出來的對象都有使用掛載在 Object.prototype 上的資源的權(quán)利。
到這里所有對象之間的關(guān)系就已經(jīng)清除了,相信已經(jīng)有不少人已經(jīng)暈乎了,沒關(guān)系 我準(zhǔn)備了圖(看不太清晰是因?yàn)樯蟼骱蟊粔嚎s了):
當(dāng)然這里我還是省略了部分細(xì)節(jié) 譬如對應(yīng)類型的 prototype 屬性對象均有 constructor 屬性指向該類型,以及省略部分類型。
對著這張圖重新看一遍本文和文章開頭的摸底,相信你會有收獲。
那么為什么使用 typeof 獲取 Object.prototype 會返回 object 呢。
我們知道瀏覽器底層對 JS 的實(shí)現(xiàn)的是基于 C/C++
通過上圖,我們可以猜測
1.用 C/C++ 構(gòu)造內(nèi)部數(shù)據(jù)結(jié)構(gòu)創(chuàng)建一個(gè) OP 即(Object.prototype)以及初始化其內(nèi)部屬性但不包括行為。
2.用 C/C++ 構(gòu)造內(nèi)部數(shù)據(jù)結(jié)構(gòu)創(chuàng)建一個(gè) FP 即(Function.prototype)以及初始化其內(nèi)部屬性但不包括行為。
3.將 FP 的[[Prototype]]指向 OP。
4.用 C/C++ 構(gòu)造內(nèi)部數(shù)據(jù)結(jié)構(gòu)創(chuàng)建各種內(nèi)置引用類型。
5.將各內(nèi)置引用類型的[[Prototype]]指向 FP。
6.將 Function 的 prototype 指向 FP。
7.將 Object 的 prototype 指向 OP。
8.用 Function 實(shí)例化出 OP,F(xiàn)P,以及 Object 的行為并掛載。
9.用 Object 實(shí)例化出除 Object 以及 Function 的其他內(nèi)置引用類型的 prototype 屬性對象。
10.用 Function 實(shí)例化出除Object 以及 Function 的其他內(nèi)置引用類型的 prototype 屬性對象的行為并掛載。
11.實(shí)例化內(nèi)置對象 Math 以及 Grobal
至此,所有 內(nèi)置類型構(gòu)建完成。
現(xiàn)在我們可以回答為什么使用 typeof 獲取 Object.prototype 會返回 object 了。
因?yàn)槲覀冊谑褂?typeof 的時(shí)候得到的 object 類型并不完全代表是 Object 類型實(shí)例化出來的對象,有可能是底層實(shí)現(xiàn)的內(nèi)部數(shù)據(jù)結(jié)構(gòu),包括 null。真正想知道這個(gè)類型還是需要去到當(dāng)前該類的內(nèi)部[[Class]]屬性,至于如何獲取可以使用Object的toString方法。
最后的最后,你還對是現(xiàn)有 Function 還是現(xiàn)有 Object 有想法了嗎?
以上均為個(gè)人查閱及實(shí)踐總結(jié)的觀點(diǎn)。
謝謝~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/79706.html
摘要:標(biāo)準(zhǔn)對象,語義由本規(guī)范定義的對象。這意味著雖然有,本質(zhì)上依然是構(gòu)造函數(shù),并不能像那樣表演多繼承嵌套類等高難度動作。不過這里的并不是我們所說的數(shù)據(jù)類型,而是對象構(gòu)造函數(shù)。 序 ECMAScript is an object-oriented programming language for performing computations and manipulating computat...
摘要:而作為構(gòu)造函數(shù),需要有個(gè)屬性用來作為以該構(gòu)造函數(shù)創(chuàng)造的實(shí)例的繼承。 歡迎來我的博客閱讀:「JavaScript 原型中的哲學(xué)思想」 記得當(dāng)年初試前端的時(shí)候,學(xué)習(xí)JavaScript過程中,原型問題一直讓我疑惑許久,那時(shí)候捧著那本著名的紅皮書,看到有關(guān)原型的講解時(shí),總是心存疑慮。 當(dāng)在JavaScript世界中走過不少旅程之后,再次萌發(fā)起研究這部分知識的欲望,翻閱了不少書籍和資料,才搞懂...
摘要:由于一般所有的原型鏈最終都會指向頂端的,所以它們都是的。好了現(xiàn)在了,成了所有對象原型鏈的。 JavaScript里任何東西都是對象,任何一個(gè)對象內(nèi)部都有另一個(gè)對象叫__proto__,即原型,它可以包含任何東西讓對象繼承。當(dāng)然__proto__本身也是一個(gè)對象,它自己也有自己的__proto__,這樣一級一級向上,就構(gòu)成了一個(gè)__proto__鏈,即原型鏈。當(dāng)然原型鏈不會無限向上,它有...
摘要:的隱式原型是母,母是由構(gòu)造函數(shù)構(gòu)造的,但函數(shù)的隱式原型又是。。。??赡苁强紤]到它也是由構(gòu)造函數(shù)生成的吧,所以返回的值也是。 showImg(https://segmentfault.com/img/bVyLk0); 首先,我們暫且把object類型和function類型分開來,因?yàn)?function是一個(gè)特殊的對象類型,我們這里這是便于區(qū)分,把function類型單獨(dú)拿出來。順便一提,...
摘要:構(gòu)造函數(shù)和實(shí)例都通過屬性指向了原形。代碼示例是構(gòu)造函數(shù)的實(shí)例的屬性與的屬性保存的值相等,即他們指向同一個(gè)對象原形。 講清楚之javascript原型 標(biāo)簽: javascript javascript 中原形是一個(gè)比較難于理解的概念。javascript 權(quán)威指南在原形這一章也花了大量的篇幅進(jìn)行介紹,也許你已經(jīng)讀過javascript 權(quán)威指南,或者已經(jīng)是讀第N篇了,然而這篇文章的目...
閱讀 3704·2021-09-02 15:11
閱讀 4682·2021-08-16 10:47
閱讀 1595·2019-08-29 18:35
閱讀 3098·2019-08-28 17:54
閱讀 2878·2019-08-26 11:37
閱讀 1533·2019-08-23 16:51
閱讀 1845·2019-08-23 14:36
閱讀 1840·2019-08-23 14:21