在討論原型前,我們需要知道什么是原型,並牢記這些鐵定規律
原型,是所有函數(構造函數)對象的一個默認屬性(prototype),它的值是一個對象{里面有什么先不管};所以我們一般說原型是構造函數的屬性,它本身也是一個對象;
原型有什么作用,原型里面的屬性和方法,可以由該構造函數創建的對象繼承(這個作用可以減少代碼的耦合);如:
function Fun(){
name : "張三"
}
此時,構造函數Fun有一個原型(默認屬性prototype),它的值是一個{},現在我們在它的原型里面添加屬性方法
Fun.prototype.a = "qq";
Fun.prototype.b= function(){
return 123;
}
現在,我們用構造函數Fun創建(new)一個對象;
var fun = new Fun();
那么根據我們的理解,此時fun對象繼承了構造函數Fun的原型里面的方法和屬性;所以
console.log(fun.a) 輸出qq
console.log(fun.b) 輸出123
此時我們可以說只要由Fun構造函數創建出來的對象,都有a和b這兩個屬性(方法)。
我們現在知道了什么是原型,但是怎么才能查看到原型呢?這里需要用到__proto__屬性
__proto__屬性(查看原型),是對象的默認屬性(注意不是所有的),它的值是創建出這個對象的構造函數的原型(prototype)
注意:__proto__的值不能通過__proto__屬性更改,只能查看,如需更改需要用到prototype;
那么我們查看下fun的原型:
fun.__proto__ ==> 創建fun對象的構造函數的原型 ==> Fun.prototype
所以,fun.__proto__ = Fun.prototype ,fun繼承了它原型(Fun.prototype)的屬性
我們再看看fun原型的原型
fun.__proto__.__proto__,即 Fun.prototype.__proto__
注意:Fun.prototype此時是一個對象,因為前面說過,原型的值是對象(一般是Object對象,部分例外)
根據剛才的推論:
Fun.prototype.__proto__ ==> 創建 Fun.prototype對象的構造函數的原型 ==>Object.prototype
Fun.prototype.__proto__ = Object.prototype 同時Fun.prototype繼承了它原型(Object.prototype)的屬性
此時,Object.prototype是最后的原型了,因為所有的對象都是由Object構造函數創建的(它自己也是的),而且Object.__prototype__的值為null;已經到了終點,即fun.__proto__.__proto__.__proto__ = null
fun.__proto__
fun.__proto__.__proto__
fun.__proto__.__proto__.__proto__
通過__proto__屬性,現在有了一條鏈,對象查找屬性(方法)時,先在自己里面找,沒有則找它的原型,還是沒有,再找它原型的原型,一直找到最后,還是沒有就返回undefined;這就是所謂的原型鏈
我們在看看Fun的原型,
因為Fun是構造函數對象,而構造函數都是通過Function創建的,所以
Fun.__proto__ = Function.prototype;一定要記住原型就是對象,也就是 Function.prototype是個對象
那么Fun原型的原型,就是
Fun.__proto__.__proto__ = Function.prototype.__proto__
Function.prototype對象的原型就是Object.prototype
Function.prototype.__proto__=Object.prototype
根據這個規律,也就是Object.prototype是所有對象的最終原型
學習原型和原型鏈的好處
對於對象的屬性和方法有了全新的認識,結構更加清晰,可以讓我少寫很多重復的代碼
fun.__proto__ = Fun.prototype
對象.__proto__ = 創建對象的構造函數.prototype
這個等式需要牢記
上面寫了一些個人對原型和原型鏈的理解,不對的地方還望多多指證
