網路上很多關於JS原型的理解,寫了很多,我也看了很多,但總是雲里霧裡,很多文章一上來就說Object是一切對象的根對象,這句話非常誤導人的思維,後來自己在控制台,自己分析出來了比較好理解的方式,下麵我來詳細屢屢關於js原型的正確理解方式。 主要是理解js中的對象,函數,函數對象,函數實例 首先我們來 ...
網路上很多關於JS原型的理解,寫了很多,我也看了很多,但總是雲里霧裡,很多文章一上來就說Object是一切對象的根對象,這句話非常誤導人的思維,後來自己在控制台,自己分析出來了比較好理解的方式,下麵我來詳細屢屢關於js原型的正確理解方式。
主要是理解js中的對象,函數,函數對象,函數實例
首先我們來聊聊這四個概念
對象
對象是什麼呢,對象就是使用json格式表示的代碼塊,用這種方式表示js中的對象如下:
{ "name":"runoob", "alexa":10000, "site":null }
JSON 對象使用在大括弧 {...} 中書寫。
對象可以包含多個 key/value(鍵/值)對。
key 必須是字元串,value 可以是合法的 JSON 數據類型(字元串, 數字, 對象, 數組, 布爾值或 null)。
key 和 value 中使用冒號 : 分割。
每個 key/value 對使用逗號 , 分割。
函數
函數就是function關鍵字定義的一段代碼塊,就是自己定義的看得到的那一塊代碼,稱之為函數,js中內置了一些基礎函數比如(Object,Date等等),其實質就是帶有構造器constructor的對象,js中可以將一個帶有構造器constructor的對象表示為為函數,函數是json對象的變體表現形式
(註意:永遠不要忘記js中的對象就是json格式的代碼塊,函數是這個json格式對象的變體)
如下為Object函數的原型Object.prototype,也是一個json鍵值對對象:
{ {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} constructor: ƒ Object() hasOwnProperty: ƒ hasOwnProperty() isPrototypeOf: ƒ isPrototypeOf() propertyIsEnumerable: ƒ propertyIsEnumerable() toLocaleString: ƒ toLocaleString() toString: ƒ toString() valueOf: ƒ valueOf() __defineGetter__: ƒ __defineGetter__() __defineSetter__: ƒ __defineSetter__() __lookupGetter__: ƒ __lookupGetter__() __lookupSetter__: ƒ __lookupSetter__() __proto__: null get __proto__: ƒ __proto__() set __proto__: ƒ __proto__() }
函數有兩種作用:一是執行特定功能的代碼塊,二是構造對象
函數對象
函數對象就是函數的原型,要與函數本身區分開來,比如Date函數的函數對象為Date.prototype,後面我在說特定函數對象的時候都會加上.prototype,因為這個函數原型才真正表述為函數對象
函數實例
函數實例就是通過函數構造器創造的對象,一個函數可以構造出多個不同的但相似的函數實例對象,例如:
function myFunction(a, b) { return a * b; } var x = myFunction (3, 3); var y = myFunction (4, 3); 從控制台可以分析出函數實例x,y是函數對象Number的子對象,其_proto_屬性指向的是Number.prototype,而不是我們通常認為的x,y為myFunction.prototype的子對象 當然這裡也不能絕對,因為函數實例的父對象是不確定的,如下實例 function myFunction2() { console.log('nihao'); } var z=myFunction2(); var m= new myFunction2();
VM360:3 nihao
undefined
z
undefined
函數實例z返回的日誌為undefined
函數實例m返回的日誌為myFunction2 {}
以上可知通過new關鍵字構造的新對象其父對象才指向其構造函數對象
對象與函數的基本認識
對象的_proto_屬性指向的是當前對象的父對象
只有函數有constructor和prototype屬性
函數中的prototype屬性字面意思是原型,指的是當前函數的對象原型,函數只是這個對象原型的變體形式
按照我的理解是這樣的,創造js這門語言的時候是定義這是一個面向對象的語言,所有首要任務就是指定對象的格式,就有json對象表示法,然後就是構造執行代碼塊的結構,即函數 表示法,再就是對象與函數的關聯,想象js一切皆為對象,函數的定義本身也是在構造對象,即定義的函數可以表示為帶有constructor的對象,這就是函數原型,然後通過函數定義法著手定義根對象就是Object.prototype以及其他的一些內置對象
關於Object與Object.prototype的理解
js中所有的對象繼承自Object.prototype這個原型對象,這個原型對象用函數表示就是Object,所以很多文章都Object為根對象,這也沒錯,因為Object表示的就是根,只是這個根是以函數的形式表示出來,而這個函數的原型就是真正的根對象,即Object.prototype:{…}(這個裡我省略了對象中的內容),這個Object.prototype派生了函數對象和普通對象(如Math,JSON等,因為這些對象中沒有構造器,可自行在控制台查看),永遠不要忘記Object這個函數是通過函數構造器構造出來的函數模樣的一塊代碼,其本質是Object.prototype這個原型,這才是根對象。
Object是一個函數,其屬性指針_proto_指向的是函數根對象ƒ () { [native code] },而函數根對象的_proto_則指向Object.prototype,應該有這樣的關係:Object._proto_._proto_===Object.prototype;
不過js在_proto_屬性後面就不讓指針跟蹤了,不過我們也可以通過變通的方式來查到,從這裡可以看出來:
Object._proto_===Function.prototype //返回值都為ƒ () { [native code] };
Function.prototype.__proto__=== Object.prototype //返回值為true
Object.prototype._proto_則為null。
以上可以看出,JS中的一切對象都是Object.prototype的子對象,函數根對象ƒ () { [native code] }是Object.prototype的子對象,函數是函數根對象ƒ () { [native code] }的子對象,Object函數也不列外。(註意Function函數是函數根對象的顯式函數聲明,代表著函數根對象,函數根對象ƒ () { [native code] }是在js運行時已經定義好了的對象)
很多文章都說所有函數都派生自這個Function對象,準確的來說應該是所有函數對象派生自Function.prototype,而Function.prototype就是ƒ () { [native code] },那麼問題來了,Object也是函數,那它也是派生自這個對象嗎,是的,前面我已經說了,Object在js中寫的時候是個函數不是根對象,而這個函數的原型Object.prototype才是真正的根對象,其形式為:這個在函數概念那裡已經表述出來了,可以返回去鞏固鞏固。
關於JS Function函數理解
JS內置對象中,Function函數(註意我這裡表述的是函數而不是函數對象,因為Function的函數對象準確來說應該為Function.prototype)較為特殊,這個理解起來就比較困難,因為Function.prototype===Function._proto_,很多人很疑惑為什麼會等於,其實這裡還缺少了一個重要的信息,那就是ƒ () { [native code] },這個才是根函數對象,這個根函數對象的父對象指向的是Object.prototype這個根對象,這是在js運行時中就已經定義好的,而Function.prototype這個函數對象原型恰好就是這個根函數對象ƒ () { [native code] },而這個Function._proto_這個屬性指針恰好就指向了ƒ () { [native code] },這都是在js運行時中定義好了, Function這個函數的作用就是為了創建函數實例的另外一種方法,其父類對象還是Object.Prototype,只是顯式定義函數的多一種選擇。
好了,文章結束,希望對各位有所幫助!