這是我在博客園的第一篇博客,早上看了一個大牛的博客,關於javascript繼承的,對於大牛使用Object.create()實現繼承的方式覺得點問題,就自己研究了一下,所以就有了這篇帖子。
本帖只講Object.create()。因為我也才做一年前端,理解不對的,希望大牛們幫忙指正。
在博客開始前先談下我多 prototype和__proto__的粗淺的認識。
1、prototype 只有類才有這個屬性,一般通過函數聲明 function xx(){} 和函數表達式 var xx=function(){} 定義的對象都有這個屬性,而通過new生成的函數對象則沒有這個屬性。類的prototype屬性指向類的原型對象
2、__proto__ 這個指向父類的prototype屬性所指向的對象,即父類的原型對象; 函數聲明和函數表達式定義的類的__proto__指向Object的原型對象function Empet(){}.比如 function A(){} ; var a= new A(); a.__proto__和A.prototype指向的是同一個對象。
3、通過new 創建的對象是沒有 prototype屬性的
先上一張圖片,這樣大家了解的比較清楚。圖應該大家都看得懂,這里就不解釋了。
基於以上粗淺的認識開始下面的探討。
先創建類A
function A(){ this.x="i am x" }
var a =new A(); console.log("A.prototype : "+A.prototype+" ,A.__proto__ : "+A.__proto__);//A.prototype : [object Object] ,A.__proto__ : function Empet(){}驗證第一點 console.log("a : "+a.prototype+" ,a.__proto__ : "+a.__proto__); //a : undefined ,a.__proto__ : [object Object] 驗證第3點
驗證驗證 第二點a.__Proto__ 就是 A.prototype
a.__proto__.getName=function(){
console.log("create by a.__proto__");
}
var a2 =new A();
a2.getName(); //create by a.__proto__
驗證成功,通過new創建的對象的__proto__跟類的prototype指向同一個對象,即類的原型對象
現在開始正題——Object.create 發生了什么
var obj =Object.create(A);
《javascript權威指南》6.1節中說 Object.create()創建一個新對象,其中第一個參數是對象的原型。
如果按照這種說法 obj.prototype 應該指向A;所以obj.prototype跟A擁有相同的方法和屬性,現在為A定義一個show方法 看obj.prototype是否能調用這個show()方法
A.show=function(){ return "i am A" } console.log("A.show(): "+A.show()); //A.show(): i am A
A能調用show方法,驗證obj.prototype 是否能調用show()方法
console.log("obj.prototype: "+obj.prototype.show());//報錯 undefined is not a function
oh,mygod,難道我心中的聖經《javascript權威指南》上寫的是錯的嗎?我寧可相信是我理解錯了,或是翻譯錯了。
經過斷點調試發現,obj擁有__proto__屬性而沒有prototype屬性。我前面也說過,在我粗淺的認識中, 只有通過new創建的對象才有這樣的性質——有__proto__屬性而沒有prototype屬性。所以我斷定obj是通過new創建的對象。斷點調試發現 obj的_proto__是指向A的。
查閱了一下資料 微軟的官方文檔上是這樣寫的
"Object.create()返回值為一個具有指定的內部原型且包含指定的屬性(如果有)的新對象" 注意這里 "指定的內部原型" 指定的內部原型是__proto__ 而不是prototype。咦,難道真的是這樣嗎?
如果是這樣的話就是說 obj是new出來的對象, 在Object.create() 過程中 產生了一個類 這個類是obj的父類。父類new出了obj這個實例對象。 父類的prototype是指向A的, 所以obj的__proto__就指向了A。
為了驗證這個想法,程序走起。
console.log("obj.__proto__.show(): "+obj.__proto__.show()); //obj.__proto__.show(): i am A
console.log("obj.x : "+obj.x); //undefined oh soga。這個是正常的,因為A中定義x是this.x="i am x" x是A實例的屬性,obj報undefined是正常的
obj的__proto__能夠調用show()方法,說明obj的__proto__確實指向A
關於第二個驗證obj.x是多余的。obj 本身沒有x屬性,沿着原型鏈 obj的prototype Object.create()創建的父類也沒有定義x。obj的prototype的prototype也就是A,A函數里面有x,但是A本身沒有定義x所以報undefined是正常的。果然基礎不夠扎實,才寫了這多余的驗證。
再隨便看下原型鏈繼承。
A.x="gg"; console.log("obj.x A have defined x : "+obj.x); //obj.x A have defined x : gg
果然跟想的一樣,obj沒有x,它就需找它的父類(obj_father),父類沒有定義this.x,注意這里是this.x 而不是父類.x(obj_father.x)。在父類中只有this.x才能被子類調用。父類.x是父類自己的私有屬性。父類沒有x所以找到父類的prototype即A。A有.x 所以就輸入A的x。沒有A沒有就報undefined;
就剛剛突發奇想 想看一下new一個實例對象會產生什么后果。
var b= new obj();//object is not a function
看到這個,我不得不嘲笑自己,本來就該這樣,都不肯思考,還要寫個程序驗證!!!基礎啊基礎
有理解不對的,希望大牛指正,不勝感激。