js的原型&原型鏈&閉包,在不少人看來是區分JS程序員水平的關鍵知識點,固然對這句話我不是十分贊同。可是掌握這幾個核心知識點老是沒錯滴!javascript
直接上代碼:java
<script type="text/javascript"> //所有爲函數對象類型(function) function f1(){} var f2 = function(){} var f3 = new Function() //所有都是普通對象類型(object) var o1 = {} var o2 = new Object() var o3 = new f1() console.info( typeof f1, typeof f2, typeof f3, typeof o1, typeof o2, typeof o3 ) //function function function object object object var obj = new f1(); f1.prototype.name = 'banyoukang'; console.info(obj.__proto__.name)//banyoukang console.info(f1.prototype)// f1 { name="banyoukang"} console.info(obj.__proto__)//f1 { name="banyoukang"} </script>
你能夠本身試試這段代碼,並想一下其輸出結果,爲何?下面讓咱們掰扯掰扯這段代碼:程序員
關於JavaScript對象
在JavaScript中,一切都是對象,可是和Java不一樣的是:這些對象是分類型的。主要分爲function(函數對象)和object(普通對象)。閉包
//所有爲函數對象類型(function) function f1(){} var f2 = function(){} var f3 = new Function() //所有都是普通對象類型(object) var o1 = {} var o2 = new Object() var o3 = new f1()
<1>在這裏,f1應該是咱們開發中最經常使用法,f2用的應該也挺多,只是多了一個引用罷了。可是,f3這種寫法卻是很少見的,其實f1,f2在建立的時候,JS會自動經過new Function()的方式來構建這些對象,因此都是f1,f2,f3本質上並無什麼區別。注:(函數
var f3 = new Function('var temp = 100; this.temp = 200; return temp + this.temp;');this
alert(f3())spa
//彈出300,()將會執行引號中的內容,相似於eval函數)prototype
<2>關於o1和o2咱們均可以理解(對象字面量、使用new表達式來建立對象),可是o3雖然是f1函數new出來的,可是和f1缺不是一個類型的,看打印結果能夠發現,一個是函數對象一個是普通對象。code
關於原型和原型鏈對象
在JavaScript中,每個對象都有一些屬性,包括prototype和__proto__,其中prototype就是原型對象(prototype其實就是函數的一個屬性),其做用就是保存對象的一些屬性和方法(你能夠經過f1.prototype.show = function(){} 給f1的prototype賦值一個方法),可是prototype對於對象自己是隱藏起來的,由於它是原型對象prototype的屬性而不是對象自己的屬性(你能夠經過f1.prototype.show()來調用,可是不能經過f1.show()來調用)。關於__proto__,這纔是原型鏈真正起做用的地方,它在普通對象和函數對象中都存在, 它的做用就是保存父類的prototype對象,JS在經過new 表達式建立一個對象的時候,一般會把父類的prototype賦值給新對象的__proto__屬性,這樣,就造成了一代代傳承...
function f2(){} f2.prototype.name='banyoukang'; var test = new f2(); console.info(test.name)//banyoukang
注:能夠經過test.__proto__來查看原型鏈
_proto_保存着父類的prototype的屬性,當查找一個屬性的時候,先看看本身有沒有這個屬性,若是沒有就順着原型鏈往上依次查找(注:不會查找自身的prototype屬性)。
3.總結
<1>prototype就是對象的一個屬性,這個屬性也是一個對象(相似Java類中把其餘類的對象定義成一個成員變量),專門用於儲存準備傳遞到子類的方法和屬性。
<2>__proto__就是prototype中屬性和方法的實際傳遞者,當你new一個對象的時候,會把父類的prototype賦值給新對象的__proto__屬性,這樣你在子類的__proto__屬性中就能夠拿到父類傳給你的屬性和方法。
<3>不一樣的對象的原型鏈是大相徑庭的,好比父類和子類:
function f1(){}
var test = new f1()
f1的原型鏈:f1->Function.prototype->Object.prototype->null
test的原型鏈:test->f1.prototype->Object.prototype->null
從上面的實例咱們能夠看到:對象的prototype屬性是爲子類服務的,是子類建立的核心,決定了子類的數據類型
這篇博文是本身試驗加上閱讀其餘大神的博客總結出來的,若是您閱讀的過程當中發現其中存在問題或者有指教的地方,歡迎拍磚,共同進步!