摘要:有個例外他就是。看左側對象的原型鏈上是否有第一步得到。將各內置引用類型的指向。用實例化出,,以及的行為并掛載。實例化內置對象以及至此,所有內置類型構建完成。最后的最后,你還對是現有還是現有有想法了嗎以上均為個人查閱及實踐總結的觀點。
來個摸底測試,說出以下每個表達式的結果
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
看到這里相信有不少入門不久的同學已經產生疑惑了 是真的嗎 然后在瀏覽器試過一番發現真是如此。
解開疑惑之前先回顧些大家都知道的知識點:
引用 MDN 關于 對象實例和對象原型對象 的闡述:
JavaScript語言的所有對象都是由Object衍生的對象;
所有對象都繼承了Object.prototype的方法和屬性,盡管它們可能被覆蓋。
例如,其它的構造器原型覆蓋了constructor屬性并提供了其自己的toString方法。
原型對象的更改會傳播給所有的對象,除非這些屬性和方法在原型鏈中被再次覆蓋。
就如我們經常在各類教科中看到的 所有的實例對象都是 Object 類型的實例
那么我們平時都是如何確定一個對象是否是另一個類型或對象的實例的呢?
對我們可以使用 typeof 關鍵字 亦或可以使用關鍵字 instanceof 來確定某個對象是否是指定類型或對象的實例:
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 這個關鍵字在表達式中發生了什么?
在弄清楚 instanceof 之前 還得弄清楚一樣東西 就是 new 一個對象到底做了什么:
如 var a = new A(); 認為 “a為A函數的實例對象”
new操作的過程是什么? 可以總結如下:
1.new 創建一個空對象{}
2.然后將A.prototype的引用放置到該對象的原型鏈上。即a.__proto__指向 A.prototype
3.執行A函數,將A中this指向該對象,執行結束,如果沒有return那么默認返回this引用
那么new的其中一個的作用便是把A.prototype的指向添加到了a的原型鏈中。
至此我們便知道了如下關系:
a.__proto__ === A.prototype //true a instanceof A //true
故為何不得出一個結論:
instanceof 操作符其實就是檢查左側的元素的 __proto__鏈上有沒有右側類或對象的prototype存在。 同理 當某某某是某某某的實例時 其實也是證明左側的__proto__鏈上有右側類或對象的prototype存在。
細節剖析如下:
1.看右側的 A 獲取其 prototype 得到 A.prototype。
2.看左側 a 對象的原型鏈上是否有第一步得到 A.prototype。
1)獲取 a.__proto__對象看是否為A.prototype,是則返回 true
2)獲取 a.__proto__.__proto__ 對象看是否為A.prototype,是則返回 true
3)重復獲取左側的原型鏈上的[[Prototype]]特性即__proto__屬性進行判斷直到為空返回 false。
校驗真理,我們都知道 js 有幾大內置類型 這些類型都是 Function 的實例,是 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 就得不出一樣的結果了呢?
我們都知道每個函數對象亦或函數類型都會有個 prototype 屬性,在其上掛載的方法和屬性均能夠被該類型實例化出來的對象共享,因為實例化出來的對象擁有 [[Prototype]]特性即 __proto__ 屬性,js 便是通過該特性實現原型鏈機制。
那么這些函數的 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
可以看出每個函數對象的 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
答案是否。
有個例外他就是 Object.prototype。
回看前面的 Demo:
Object.prototype instanceof Object // false
從前面的代碼輸出我們看到 Object.prototype 對象是沒有[[Prototype]]特性的,同時前面我們也討論過 instanceof 這個關鍵字所涉及的具體操作。
我們可以具體剖析如下:
1.看右側的 Object 獲取其 prototype 得到 Object.prototype。
2.看左側 Object.prototype 對象的原型鏈上是否有第一步得到 Object.prototype。
1)獲取 Object.prototype.__proto__對象為空直接返回 false。
那么為什么所有的對象都有[[Prototype]] 特性,唯獨Object.prototype沒有呢。答案很簡單:既然 JS的繼承機制是基于原型鏈的那總該有個頭吧,這個頭便是Object.prototype 。
再來一發:
out( typeof Function) //function out( typeof Object) //function out( Object instanceof Function) //true out( Function instanceof Function) //true
在學習 JS 的過程中我們已經知道所有的數據類型都是 Function 類型的實例,包括 Object 在內,但是我們都知道所有的對象都是 Object 的實例,這時便引出文章的題目
到底是先有 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
從上述代碼加上前面得出的結論我們可以看出
Function 和 Object 的原型鏈上都有 Function.prototype
我們再來詳細看看 Function.prototype
out( typeof Function.prototype); // function out( Function.prototype instanceof Object) //true
這時候問題升華為
Function.prototype 和 Object.prototype 的關系。out( Function.prototype.__proto__ === Object.prototype)
這時候關系已經很明了了:
我們都知道除了 Object.prototype 之外所有對象都會有[[Prototype]]特性 即 __proto__ 屬性,故 Function.prototype 也不例外,
Function.prototype 指向的是 Object.prototype
這時候就可以清楚的知道為什么說所有類型都是 Function 的實例,同時也是 Object 的實例:
因為所有的類型的[[Prototype]]特性 即 __proto__ 屬性均指向的是 Function.prototype ,同時 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。
我們知道當一個類型實例化出對象時,這些對象的便會共享掛載在該類型的 prototype 屬性上的 資源,因為這些對象均有[[Prototype]]特性,指向的就是實例化出這些對象的類型的 prototype
從前面的例子可以看到所有的類型的[[Prototype]]特性均指向了 Function.prototype,所以這些類型都具有了使用掛載在Function.prototype上的資源的權利。因此可以看出,當一個對象具有使用掛載在Function.prototype上的資源的權利時,及該對象[[Prototype]]指向 Function.prototype 時代表這個對象是個 Function 實例是一個類型,能夠實例化出該類型的對象,當然包括 Function 在內。
又因為所有類型的[[Prototype]]指向 Function.prototype 而 Function.prototype 的[[Prototype]]指向是 Object.prototype,所以這些類型都具有使用掛載在 Object.prototype 上的資源的權利。
那用這些類型實例化出來的對象呢 類型的原型鏈并不在實例化出來的對象上呀,但是這些實例化出來的對象的[[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 故至此,所有對象包括類型對象亦或類型實例化出來的對象都有使用掛載在 Object.prototype 上的資源的權利。
到這里所有對象之間的關系就已經清除了,相信已經有不少人已經暈乎了,沒關系 我準備了圖(看不太清晰是因為上傳后被壓縮了):
當然這里我還是省略了部分細節 譬如對應類型的 prototype 屬性對象均有 constructor 屬性指向該類型,以及省略部分類型。
對著這張圖重新看一遍本文和文章開頭的摸底,相信你會有收獲。
那么為什么使用 typeof 獲取 Object.prototype 會返回 object 呢。
我們知道瀏覽器底層對 JS 的實現的是基于 C/C++
通過上圖,我們可以猜測
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
至此,所有 內置類型構建完成。
現在我們可以回答為什么使用 typeof 獲取 Object.prototype 會返回 object 了。
因為我們在使用 typeof 的時候得到的 object 類型并不完全代表是 Object 類型實例化出來的對象,有可能是底層實現的內部數據結構,包括 null。真正想知道這個類型還是需要去到當前該類的內部[[Class]]屬性,至于如何獲取可以使用Object的toString方法。
最后的最后,你還對是現有 Function 還是現有 Object 有想法了嗎?
以上均為個人查閱及實踐總結的觀點。
謝謝~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79706.html
摘要:標準對象,語義由本規范定義的對象。這意味著雖然有,本質上依然是構造函數,并不能像那樣表演多繼承嵌套類等高難度動作。不過這里的并不是我們所說的數據類型,而是對象構造函數。 序 ECMAScript is an object-oriented programming language for performing computations and manipulating computat...
摘要:而作為構造函數,需要有個屬性用來作為以該構造函數創造的實例的繼承。 歡迎來我的博客閱讀:「JavaScript 原型中的哲學思想」 記得當年初試前端的時候,學習JavaScript過程中,原型問題一直讓我疑惑許久,那時候捧著那本著名的紅皮書,看到有關原型的講解時,總是心存疑慮。 當在JavaScript世界中走過不少旅程之后,再次萌發起研究這部分知識的欲望,翻閱了不少書籍和資料,才搞懂...
摘要:由于一般所有的原型鏈最終都會指向頂端的,所以它們都是的。好了現在了,成了所有對象原型鏈的。 JavaScript里任何東西都是對象,任何一個對象內部都有另一個對象叫__proto__,即原型,它可以包含任何東西讓對象繼承。當然__proto__本身也是一個對象,它自己也有自己的__proto__,這樣一級一級向上,就構成了一個__proto__鏈,即原型鏈。當然原型鏈不會無限向上,它有...
摘要:的隱式原型是母,母是由構造函數構造的,但函數的隱式原型又是。。。。可能是考慮到它也是由構造函數生成的吧,所以返回的值也是。 showImg(https://segmentfault.com/img/bVyLk0); 首先,我們暫且把object類型和function類型分開來,因為 function是一個特殊的對象類型,我們這里這是便于區分,把function類型單獨拿出來。順便一提,...
摘要:構造函數和實例都通過屬性指向了原形。代碼示例是構造函數的實例的屬性與的屬性保存的值相等,即他們指向同一個對象原形。 講清楚之javascript原型 標簽: javascript javascript 中原形是一個比較難于理解的概念。javascript 權威指南在原形這一章也花了大量的篇幅進行介紹,也許你已經讀過javascript 權威指南,或者已經是讀第N篇了,然而這篇文章的目...
閱讀 3652·2021-09-02 15:11
閱讀 4563·2021-08-16 10:47
閱讀 1560·2019-08-29 18:35
閱讀 3030·2019-08-28 17:54
閱讀 2843·2019-08-26 11:37
閱讀 1496·2019-08-23 16:51
閱讀 1799·2019-08-23 14:36
閱讀 1801·2019-08-23 14:21