Javascript的構(gòu)造函數(shù)和constructor屬性
然而事情并不是這么簡單。再看下面的代碼:

很顯然,這個時候obj的constructor已經(jīng)不再是創(chuàng)建它的函數(shù),注意到obj.name也是undefined,因此修改構(gòu)造函數(shù)的prototype的contructor并不會影響構(gòu)造函數(shù)所產(chǎn)生的對象。真正的原因是:一個對象的constructor是它的構(gòu)造函數(shù)的prototype.constructor,而每一個函數(shù)都有一個prototype,默認情況下,這個prototype有一個constructor屬性,指向的是它自己。 我覺得Javascript的設(shè)計本意是讓每個對象的constructor都指向自己的構(gòu)造函數(shù),然而有像上面的例子可以破壞這一點。另外,這樣的設(shè)計其實也不很完美,一個很大的問題就是在繼承的時候必須小心的維護constructor的指向。在最簡單的繼承中,可以把子類的構(gòu)造函數(shù)的prototype設(shè)置為父類的一個實例,而父類的實例的constructor是父類的構(gòu)造函數(shù),從而子類的prototype的constructor是父類的構(gòu)造函數(shù),這就造成了子類的每個對象的構(gòu)造函數(shù)都是父類的構(gòu)造函數(shù)。這是很容易引起困惑的。
最后,再回到上一篇遺留下來的問題,上文談到Extjs官網(wǎng)給出的一個繼承Observable的例子:
Employee = Ext.extend(Ext.util.Observable, {
constructor: function(config){
this.name = config.name;
this.addEvents({
"fired" : true,
"quit" : true
});
// Copy configured listeners into *this* object so that the base class's
// constructor will add them.
this.listeners = config.listeners;
// Call our superclass constructor to complete construction process.
Employee.superclass.constructor.call(config)
}
});
這個例子給人的錯覺就是你可以重寫父類的constructor屬性,從而達到改變子類的構(gòu)造函數(shù)的行為的效果。這對于Javascript基礎(chǔ)卻不深的人是一種誤導(dǎo)。 我們再仔細看下Ext.extend的源代碼:
extend : function(){
// inline overrides
var io = function(o){
for(var m in o){
this[m] = o[m];
}
};
var oc = Object.prototype.constructor;
return function(sb, sp, overrides){
if(Ext.isObject(sp)){
overrides = sp;
sp = sb;
sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);}; //注意這里 }
//以下省略………}(), 請注意加注釋的那一行。extend如果檢測到overrides參數(shù)中有constructor屬性,也就是說子類試圖改寫父類的prototype的constructor的時候,就直接將子類設(shè)置為這個函數(shù)!這樣就達到效果了。不過我立刻發(fā)現(xiàn)這句檢測僅在這個if語句塊中,也就是extend的兩參數(shù)版本中有,那么使用extend的另一個三參數(shù)版本這樣設(shè)置應(yīng)該是無效的。 寫段代碼測試下:
<head>
<title></title>
<script type="text/javascript" src="ext-3.1.0/src/core/core/Ext.js"></script>
<script type="text/javascript">
function MyClass() {
this.id = 'class';
}
function SubClass() { }
// SubClass=Ext.extend(SubClass, MyClass, { constructor: function() {
// this.overrideProperty = 'OK';
// }
// });
SubClass = Ext.extend(MyClass, { constructor: function() {
this.overrideProperty = 'OK';
}
});
var obj = new SubClass();
alert(obj.overrideProperty);
</script>
</head>
兩種寫法,運行的結(jié)果果然是第一種是undefined而第二種是OK。呃,名字相同的函數(shù)僅僅是參數(shù)寫法不同,執(zhí)行的效果卻不相同,這個是有點出乎意料的。而且Extjs的官方文檔未對此有任何說明。以后大家還是盡量用兩參數(shù)版本的吧。
最后順便再看幾個表達式,
第一個是說函數(shù)的prototype的constructor是自己,這個上文已經(jīng)談到,沒有問題;第二個是說函數(shù)也是一個對象,它是Function構(gòu)造函數(shù)的一個對象,也還好理解;第三個是說Function構(gòu)造函數(shù)本身一個對象,它還是Function構(gòu)造函數(shù)的一個對象;最后一個其實是和第三個等價的,是說Function對象的構(gòu)造函數(shù)是它自己…… 我確實有點想不明白Function是怎么自己構(gòu)造自己的?雞生蛋,蛋生雞?要再追究下去就應(yīng)該涉及到Javascript語言的具體實現(xiàn)了吧,就此打住。
哎,Javascript這個語言本身還是有點復(fù)雜啊。要不是有了XMLHttpObject,讓它大紅大紫了下,否則它還在黑暗的角落里暗自哭泣呢。
作為應(yīng)用程序開發(fā)人員,或許我們自己寫程序的并不會用到這些底層的東西,但是,JS框架中卻大量的使用了這些高級特性,而且再詳盡的文檔也不可能把這些方法的作用、影響一一道來,所以開發(fā)人員還是需要盡量理解這些東西,以免死了還不知道怎么回事。上面的Ext.extend函數(shù)就是一個例子。
- js核心基礎(chǔ)之構(gòu)造函數(shù)constructor用法實例分析
- JavaScript精煉之構(gòu)造函數(shù) Constructor及Constructor屬性詳解
- 不用構(gòu)造函數(shù)(Constructor)new關(guān)鍵字也能實現(xiàn)JavaScript的面向?qū)ο?/a>
- javascript prototype的深度探索不是原型繼承那么簡單
- JavaScript為對象原型prototype添加屬性的兩種方式
- js中使用使用原型(prototype)定義方法的好處詳解
- javascript prototype原型詳解(比較基礎(chǔ))
- JavaScript中的原型prototype完全解析
- JS構(gòu)造函數(shù)與原型prototype的區(qū)別介紹
- js使用原型對象(prototype)需要注意的地方
- js構(gòu)造函數(shù)constructor和原型prototype原理與用法實例分析
相關(guān)文章
利用jsonp跨域調(diào)用百度js實現(xiàn)搜索框智能提示
這篇文章主要為大家詳細介紹了使用jsonp跨域調(diào)用百度js實現(xiàn)搜索框智能提示,感興趣的小伙伴們可以參考一下2016-08-08
asp.net下利用js實現(xiàn)返回上一頁的實現(xiàn)方法小集
其實要實現(xiàn)這個功能主要還是要用到j(luò)avascript2009-11-11
js實現(xiàn)無限層級樹形數(shù)據(jù)結(jié)構(gòu)(創(chuàng)新算法)
這篇文章主要介紹了js實現(xiàn)無限層級樹形數(shù)據(jù)結(jié)構(gòu),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02


