JavaScript constructor和instanceof,JSOO中的一對歡喜冤家
更新時間:2009年05月25日 02:55:12 作者:
現(xiàn)在流行面向?qū)ο?JavaScript當(dāng)然要迎頭趕上.
有說法JavaScript就是徹頭徹尾的OO語言,但我覺得JavaScript實現(xiàn)面向?qū)ο蟮某绦蜻€是有諸多不便的.
至少每個嘗試JavaScriptOO的程序員都花費很多精力用在面向?qū)ο髾C制的模擬上而非業(yè)務(wù)本身.
這對Java,C++甚至Php的開發(fā)者來講都是難以想象的.
更糟糕的是模擬OO對于JavaScript高級程序員都有著邪惡的吸引.
因為干這個事兒超然于業(yè)務(wù)之上,有種創(chuàng)造新編程語言一般的快感,可以令I(lǐng)Q盡情揮灑.
正如前些年大家都想把自個網(wǎng)站的common.js寫成個框架一樣.直到Y(jié)UI,JQuery等等的強勢推出才稍有平息.
然而雖然各個框架都有對JavaScriptOO模擬,但還未到有誰誰誰可以一桶糨糊的時候吧.
或許江湖就不需要的霸主出現(xiàn),抑或大家只要等到JS2.0+就好了.
如果說可以new就是面向?qū)ο?那顯然JavaScript在這方面是非常不錯的.
function Person(name){
this.name = name;
}
var lenel = new person("lenel");
alert(lenel.constructor === Person);
alert(lenel instanceof Person === true);
alert(lenel instanceof Object === true);
到此為止,一切都很和諧.
對象的constructor正如字面上的意義指向構(gòu)造它的Person.
對象是構(gòu)造它的Person的一個實例(instance).
所有對象都是Object的實例,像極了Java.
JavaScript提供原型(prototype)的方式來實現(xiàn)方法拓展和繼承
Person.prototype.getName = function(){
return this.name
};
這樣定義了之后所有對象都具有了getName的方法.
當(dāng)然也可以將寫在對象構(gòu)造時
function Person(name){
this.name = name;
this.getName = function(){
return this.name;
};
}
但是這種做法不僅是帶來額外性能損耗這點瑕疵,也不僅是帶來了可以訪問私有變量的特權(quán).
它與使用prototype的寫法還會其他有不同之處,不過這不是本文的重點.
接下來,我們想到繼承,很常見的寫法是這樣的.
function Stuff(name,id){
this.name = name;
this.id = id;
}
Stuff.prototype = new Person();
var piupiu = new Stuff("piupiu","007");
alert(piupiu.getName());
非常好,繼承了getName方法;
考察下instanceof
alert(piupiu instanceof Stuff === true);
alert(piupiu instanceof Person === true);
非常好,說明了Stuff和Person是有關(guān)系的.piupiu是它倆的實例,非常Java.
接下來再考察下constructor
alert(piupiu.constructor === Stuff);//false
test(piupiu.constructor === Person);//true
問題出現(xiàn)了明明new的Stuff為啥constructor卻是Person,
在這兒將道理也是強詞奪理,我們只好記住結(jié)論
結(jié)論:對象的constructor屬性并非指向其構(gòu)造器,而是指向其構(gòu)造器的prototype屬性的constructor屬性
文字功底太差,自己讀過都覺得沒說清楚
放在這里:
對象piupiu的constructor屬性指向的是其構(gòu)造器Stuff的prototype屬性的constructor屬性
因為Stuff.prototype = new Person();
所以Stuff.prototype.constructor === Person.
所以piupiu.consturctor === Person.
以上的結(jié)論不僅僅在對象繼承的時候才出現(xiàn),在定義對象時
function Student(name){
this.name = name;
}
Student.prototype = {
getName:function(){
return this.name;
},
setName:function(name){
this.name = name;
}
}
如果方法比較多,常常會這樣寫,看起來規(guī)矩一些.
其實這種寫法同樣犧牲了constructor
var moen = new Student("moen");
alert(moen.constructor === Student);//false
alert(moen.constructor === Object);//true
因為在{}相當(dāng)于new Object(),所以根據(jù)上面的結(jié)論prototype={}時,constructor變了.
保衛(wèi)constructor!繼承時我們用一個循環(huán)來把父類的方法copyto子類
function Stuff1(name,id){
this.name = name;
this.id = id;
}
for(var fn in Person.prototype){
Stuff1.prototype[fn] = Person.prototype[fn];
}
var piupiu1 = new Stuff1("piupiu1","008");
alert(piupiu1.getName() === "piupiu1");
alert(piupiu1.constructor === Stuff1);
It works!當(dāng)我們興沖沖的把父類的方法都繼承下來的時候,我們卻丟失了父子關(guān)系.
alert(piupiu1 instanceof Stuff1 === true);//true
alert(piupiu1 instanceof Person === true);//false
顯然,我們沒有說過Stuff1是繼承至Person啊,只一個for循環(huán)能說明什么呢.
這好像是一對矛盾..顧此必失彼.
所以叻,深入使用對象的時候,甚至你一不小心,都會讓instantceof和constructor丟去字面的含義.
所以叻,在使用框架的時候,如果提供了繼承功能,如果不試不會知道你為了繼承放棄了哪個.
所以叻,模擬OO時就必須要提供替代這兩個字面含義的屬性或方法的實現(xiàn),而且必須讓使用者知道!
模擬OO絕對不只這個問題,在子類方法中調(diào)用父類的同名方法,這個OO語言常見的特性,
JavaScript實現(xiàn)起來也非常困難,大師們基本都有各自的一套,只不過有些用心去做了用起來相比之下更自然些,如Base庫.
當(dāng)然可以摒棄instanceof和constructor的使用,就當(dāng)不知道有這么一回兒事兒,活兒仍可繼續(xù),死不了人的.
但如果你不是單槍匹馬作戰(zhàn),那就通知你的Partner也摒棄這對冤家吧.
類似今天這點事兒,老鳥們都清楚的很,但如果不是團(tuán)隊中每個人都有統(tǒng)一的認(rèn)識,那就是隱患.
一個好玩兒的現(xiàn)象<<JavaScript高級程序設(shè)計>>強調(diào)instanceof,而<<精通JavaScript>>強調(diào)constructor.而各自對另一個一筆帶過或只字不提.怨念..甚深...
這對Java,C++甚至Php的開發(fā)者來講都是難以想象的.
更糟糕的是模擬OO對于JavaScript高級程序員都有著邪惡的吸引.
因為干這個事兒超然于業(yè)務(wù)之上,有種創(chuàng)造新編程語言一般的快感,可以令I(lǐng)Q盡情揮灑.
正如前些年大家都想把自個網(wǎng)站的common.js寫成個框架一樣.直到Y(jié)UI,JQuery等等的強勢推出才稍有平息.
然而雖然各個框架都有對JavaScriptOO模擬,但還未到有誰誰誰可以一桶糨糊的時候吧.
或許江湖就不需要的霸主出現(xiàn),抑或大家只要等到JS2.0+就好了.
如果說可以new就是面向?qū)ο?那顯然JavaScript在這方面是非常不錯的.
復(fù)制代碼 代碼如下:
function Person(name){
this.name = name;
}
var lenel = new person("lenel");
alert(lenel.constructor === Person);
alert(lenel instanceof Person === true);
alert(lenel instanceof Object === true);
到此為止,一切都很和諧.
對象的constructor正如字面上的意義指向構(gòu)造它的Person.
對象是構(gòu)造它的Person的一個實例(instance).
所有對象都是Object的實例,像極了Java.
JavaScript提供原型(prototype)的方式來實現(xiàn)方法拓展和繼承
復(fù)制代碼 代碼如下:
Person.prototype.getName = function(){
return this.name
};
這樣定義了之后所有對象都具有了getName的方法.
當(dāng)然也可以將寫在對象構(gòu)造時
復(fù)制代碼 代碼如下:
function Person(name){
this.name = name;
this.getName = function(){
return this.name;
};
}
但是這種做法不僅是帶來額外性能損耗這點瑕疵,也不僅是帶來了可以訪問私有變量的特權(quán).
它與使用prototype的寫法還會其他有不同之處,不過這不是本文的重點.
接下來,我們想到繼承,很常見的寫法是這樣的.
復(fù)制代碼 代碼如下:
function Stuff(name,id){
this.name = name;
this.id = id;
}
Stuff.prototype = new Person();
var piupiu = new Stuff("piupiu","007");
alert(piupiu.getName());
非常好,繼承了getName方法;
考察下instanceof
復(fù)制代碼 代碼如下:
alert(piupiu instanceof Stuff === true);
alert(piupiu instanceof Person === true);
非常好,說明了Stuff和Person是有關(guān)系的.piupiu是它倆的實例,非常Java.
接下來再考察下constructor
復(fù)制代碼 代碼如下:
alert(piupiu.constructor === Stuff);//false
test(piupiu.constructor === Person);//true
問題出現(xiàn)了明明new的Stuff為啥constructor卻是Person,
在這兒將道理也是強詞奪理,我們只好記住結(jié)論
結(jié)論:對象的constructor屬性并非指向其構(gòu)造器,而是指向其構(gòu)造器的prototype屬性的constructor屬性
文字功底太差,自己讀過都覺得沒說清楚
放在這里:
對象piupiu的constructor屬性指向的是其構(gòu)造器Stuff的prototype屬性的constructor屬性
因為Stuff.prototype = new Person();
所以Stuff.prototype.constructor === Person.
所以piupiu.consturctor === Person.
以上的結(jié)論不僅僅在對象繼承的時候才出現(xiàn),在定義對象時
復(fù)制代碼 代碼如下:
function Student(name){
this.name = name;
}
Student.prototype = {
getName:function(){
return this.name;
},
setName:function(name){
this.name = name;
}
}
如果方法比較多,常常會這樣寫,看起來規(guī)矩一些.
其實這種寫法同樣犧牲了constructor
復(fù)制代碼 代碼如下:
var moen = new Student("moen");
alert(moen.constructor === Student);//false
alert(moen.constructor === Object);//true
因為在{}相當(dāng)于new Object(),所以根據(jù)上面的結(jié)論prototype={}時,constructor變了.
保衛(wèi)constructor!繼承時我們用一個循環(huán)來把父類的方法copyto子類
復(fù)制代碼 代碼如下:
function Stuff1(name,id){
this.name = name;
this.id = id;
}
for(var fn in Person.prototype){
Stuff1.prototype[fn] = Person.prototype[fn];
}
var piupiu1 = new Stuff1("piupiu1","008");
alert(piupiu1.getName() === "piupiu1");
alert(piupiu1.constructor === Stuff1);
It works!當(dāng)我們興沖沖的把父類的方法都繼承下來的時候,我們卻丟失了父子關(guān)系.
復(fù)制代碼 代碼如下:
alert(piupiu1 instanceof Stuff1 === true);//true
alert(piupiu1 instanceof Person === true);//false
顯然,我們沒有說過Stuff1是繼承至Person啊,只一個for循環(huán)能說明什么呢.
這好像是一對矛盾..顧此必失彼.
所以叻,深入使用對象的時候,甚至你一不小心,都會讓instantceof和constructor丟去字面的含義.
所以叻,在使用框架的時候,如果提供了繼承功能,如果不試不會知道你為了繼承放棄了哪個.
所以叻,模擬OO時就必須要提供替代這兩個字面含義的屬性或方法的實現(xiàn),而且必須讓使用者知道!
模擬OO絕對不只這個問題,在子類方法中調(diào)用父類的同名方法,這個OO語言常見的特性,
JavaScript實現(xiàn)起來也非常困難,大師們基本都有各自的一套,只不過有些用心去做了用起來相比之下更自然些,如Base庫.
當(dāng)然可以摒棄instanceof和constructor的使用,就當(dāng)不知道有這么一回兒事兒,活兒仍可繼續(xù),死不了人的.
但如果你不是單槍匹馬作戰(zhàn),那就通知你的Partner也摒棄這對冤家吧.
類似今天這點事兒,老鳥們都清楚的很,但如果不是團(tuán)隊中每個人都有統(tǒng)一的認(rèn)識,那就是隱患.
一個好玩兒的現(xiàn)象<<JavaScript高級程序設(shè)計>>強調(diào)instanceof,而<<精通JavaScript>>強調(diào)constructor.而各自對另一個一筆帶過或只字不提.怨念..甚深...
您可能感興趣的文章:
- js constructor的實際作用分析
- Javascript的構(gòu)造函數(shù)和constructor屬性
- 理解Javascript_11_constructor實現(xiàn)原理
- 深入分析js中的constructor和prototype
- JavaScript類和繼承 constructor屬性
- JavaScript中幾個重要的屬性(this、constructor、prototype)介紹
- JavaScript中的prototype和constructor簡明總結(jié)
- javascript new后的constructor屬性
- 不用構(gòu)造函數(shù)(Constructor)new關(guān)鍵字也能實現(xiàn)JavaScript的面向?qū)ο?/a>
- javascript設(shè)計模式Constructor(構(gòu)造器)模式
相關(guān)文章
JavaScript創(chuàng)建對象的常用方式總結(jié)
這篇文章主要介紹了JavaScript創(chuàng)建對象的常用方式,結(jié)合實例形式總結(jié)分析了javascript面向?qū)ο蟪绦蛟O(shè)計中對象創(chuàng)建的常見方式、相關(guān)操作技巧與注意事項,需要的朋友可以參考下2018-08-08javascript實現(xiàn)選中復(fù)選框后相關(guān)輸入框變灰不可用的方法
這篇文章主要介紹了javascript實現(xiàn)選中復(fù)選框后相關(guān)輸入框變灰不可用的方法,涉及javascript針對頁面元素屬性的相關(guān)操作技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-08-08深入理解JavaScript系列(27):設(shè)計模式之建造者模式詳解
這篇文章主要介紹了深入理解JavaScript系列(27):設(shè)計模式之建造者模式詳解,建造者模式可以將一個復(fù)雜對象的構(gòu)建與其表示相分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示,需要的朋友可以參考下2015-03-03javascript實現(xiàn)的LI列表輸出,隔行同色的代碼
javascript實現(xiàn)的LI列表輸出,隔行同色的代碼...2007-10-10使用js判斷數(shù)組中是否包含某一元素(類似于php中的in_array())
這篇文章主要是對使用js判斷數(shù)組中是否包含某一元素(類似于php中的in_array())需要的朋友可以過來參考下,希望對大家有所幫助2013-12-12JS實現(xiàn)PC手機端和嵌入式滑動拼圖驗證碼三種效果
這篇文章主要介紹了JS實現(xiàn)PC手機端和嵌入式滑動拼圖驗證碼三種效果,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-02-02document.getElementById為空或不是對象的解決方法
document.getElementById為空或不是對象的解決方法,一般情況下注意先內(nèi)容后js.2010-01-01