Ext.extend用法以及代碼解讀
概述
Ext.extend是Ext的繼承機(jī)制,這個函數(shù)的代碼相當(dāng)難懂。要明白這個函數(shù)的代碼,首先要知道這個函數(shù)如何使用。
使用方式
使用示例
假設(shè)有個function名為SuperClass,要實現(xiàn)一個子類,名為MyClass。下面的兩種方式都可以實現(xiàn)這個功能。
MyClass = Ext.extend(SuperClass, { /* */ }); Ext.extend(MyClass, SuperClass, { /* */}); |
下面來個具體示例:
var a = function(id){ this.id = id; } a.prototype = { tostring : function(){ return this.id; } }; b = function(id){ b.superclass.constructor.call(this, id); } Ext.extend(b, a, { tostring : function(){ return String.format("b:{0}", this.id); } }); //測試一下 var obj1 = new a("obj1"); alert(obj1.tostring()); var obj2 = new b("obj2"); alert(obj2.tostring()); |
或者下面的代碼,可以得到同樣的效果:
var a = function(id){ this.id = id; } a.prototype = { tostring : function(){ return this.id; } }; b = Ext.extend(a, { tostring : function(){ return String.format("b:{0}", this.id); } }); //測試一下 var obj1 = new a("obj1"); alert(obj1.tostring()); var obj2 = new b("obj2"); alert(obj2.tostring()); |
一個錯誤例子
下面看個示例:
BaseClass = function() { this.f1 = function() { alert("f } this.f2 = function() { alert("f } } ChildClass = function() { ChildClass.superclass.constructor.call(this); } Ext.extend(ChildClass, BaseClass, { f1: function() { alert("f }, f3: function() { alert("f } }); var b = new ChildClass(); b.f1(); b.f2(); b.f3(); |
可以去執(zhí)行一下,可以發(fā)現(xiàn)f1的執(zhí)行結(jié)果仍然是"f
Ext.extend puts the properties specified in the 3rd argument into the subclass's prototype |
也就是說:第三個參數(shù)里面的函數(shù)被放置在了子類的prototype中。
而在ChildClass.superclass.constructor.call(this);這句上,BaseClass的f1成了ChildClass的變量,而不是ChildClass.prototype。通過對JavaScript的原型繼承的了解,可以知道,實例變量的優(yōu)先級是高于prototype的,所以上面的這個代碼是達(dá)不到override的功能的。
修改的方式如下:
BaseClass = function() { }; BaseClass.prototype = { f1: function() { alert("f } }; |
代碼解讀
JavaScript中的繼承實現(xiàn)
先了解一下最簡單的繼承是如何實現(xiàn)的:
function Extend(subFn, superFn){ subFn.prototype = new superFn() subFn.prototype.constructor = subFn } function Animal(){ this.say1 = function(){ alert("Animal"); } } function Tiger(){ this.say2 = function(){ alert("Tiger"); } } Extend(Tiger,Animal); var tiger = new Tiger(); tiger.say1();//"Animal" tiger.say2();//"Tiger" |
可以看到最簡單的繼承只做了兩件事情,一是把subFn的prototype設(shè)置為superFn的一個實例,然后設(shè)置subFn.prototype.constructor為subFn。
Ext.extend的代碼
Ext.extend函數(shù)中用到了Ext.override,這個函數(shù)把第二個參數(shù)中的所有對象復(fù)制到第一個對象的prototype中。首先貼上Ext.override函數(shù)的代碼:
Ext.override = function(origclass, overrides){ if(overrides){ var p = origclass.prototype; for(var method in overrides){ p[method] = overrides[method]; } } } |
然后貼上Ext.extend的代碼:
/** * 繼承,并由傳遞的值決定是否覆蓋原對象的屬性 * 返回的對象中也增加了override()函數(shù),用于覆蓋實例的成員 * @param {Object} subclass 子類,用于繼承(該類繼承了父類所有屬性,并最終返回該對象) * @param {Object} superclass 父類,被繼承 * @param {Object} overrides (該參數(shù)可選) 一個對象,將它本身攜帶的屬性對子類進(jìn)行覆蓋 * @method extend */ function extend (){ // inline overrides var io = function(o){ for(var m in o){ this[m] = o[m]; } }; return function(sb, sp, overrides){ if(typeof sp == 'object'){ overrides = sp; sp = sb; sb = function(){sp.apply(this, arguments);}; } var F = function(){}, sbp, spp = sp.prototype; F.prototype = spp; sbp = sb.prototype = new F(); sbp.constructor=sb; sb.superclass=spp; if(spp.constructor == Object.prototype.constructor){ spp.constructor=sp; } sb.override = function(o){ Ext.override(sb, o); }; sbp.override = io; Ext.override(sb, overrides); return sb; }; }(); |
代碼中進(jìn)行了太多的簡寫,看起來不是特別方便,把代碼中的簡寫補(bǔ)全,代碼如下:
function extend(){ // inline overrides var inlineOverride = function(o){ for (var m in o) { this[m] = o[m]; } }; return function(subFn, superFn, overrides){ if (typeof superFn == 'object') { //如果subFn也是對象的話(一般來說subFn這里放的是父類的構(gòu)造函數(shù)),那么第三個參數(shù)overrides參數(shù)相當(dāng)于被忽略掉 overrides = superFn; superFn = subFn; //subFn重新定義了函數(shù) subFn = function(){ superFn.apply(this, arguments); }; } var F = function(){ }, subFnPrototype, superFnPrototype = superFn.prototype; F.prototype = superFnPrototype; subFnPrototype = subFn.prototype = new F(); subFnPrototype.constructor = subFn; subFn.superclass = superFnPrototype; if (superFnPrototype.constructor == Object.prototype.constructor) { superFnPrototype.constructor = superFn; } subFn.override = function(obj){ Ext.override(subFn, obj); }; subFnPrototype.override = inlineOverride; Ext.override(subFn, overrides); return subFn; }; }; |
補(bǔ)全以后也不是特別容易明白,那么我們就把這個代碼分開,分為2個參數(shù)和3個參數(shù)。
兩個參數(shù)的Ext.extend代碼
首先把代碼改寫成兩個參數(shù)的。
//兩個參數(shù)的時候的代碼,注意第二個參數(shù)必須為object function extend(){ // inline overrides var inlineOverride = function(o){ for (var m in o) { this[m] = o[m]; } }; return function(superFn, overrides){ var subFn = function(){ superFn.apply(this, arguments); }; var F = function(){ }, subFnPrototype, superFnPrototype = superFn.prototype; F.prototype = superFnPrototype; //注意下面兩句就是上面最簡單的繼承實現(xiàn)。 subFnPrototype = subFn.prototype = new F(); subFnPrototype.constructor = subFn; //添加了superclass屬性指向superFn的Prototype subFn.superclass = superFnPrototype; //為subFn和subFnPrototype添加override函數(shù) subFn.override = function(obj){ Ext.override(subFn, obj); }; subFnPrototype.override = inlineOverride; //覆蓋掉子類prototype中的屬性 Ext.override(subFn, overrides); return subFn; }; }; |
從注釋中可以看到,做的工作很簡單,只是定義一個subFn函數(shù),這個函數(shù)中會調(diào)用superFn函數(shù)。定義了subFn以后,就使用上面的最簡單的繼承方式實現(xiàn)繼承。然后為subFn和subFn的prototype添加了一個override函數(shù)。最后的Ext.override(subFn, overrides);把overrides中的函數(shù)寫入subFn的prototype中。
三個參數(shù)的Ext.extend代碼
下面我們把函數(shù)改寫為只處理3個參數(shù)的,改寫后的代碼如下:
//三個參數(shù)時的代碼 function extend(){ // inline overrides var inlineOverride = function(o){ for (var m in o) { this[m] = o[m]; } }; return function(subFn, superFn, overrides){ var F = function(){ }, subFnPrototype, superFnPrototype = superFn.prototype; F.prototype = superFnPrototype; //注意下面兩句就是上面最簡單的繼承實現(xiàn)。 subFnPrototype = subFn.prototype = new F(); subFnPrototype.constructor = subFn; //添加了superclass屬性指向superFn的Prototype subFn.superclass = superFnPrototype; //為subFn和subFnPrototype添加override函數(shù) subFn.override = function(obj){ Ext.override(subFn, obj); }; subFnPrototype.override = inlineOverride; //覆蓋掉子類prototype中的屬性 Ext.override(subFn, overrides); return subFn; }; }; |
過程與兩個參數(shù)的時候相差無幾,只是兩個參數(shù)的時候,subFn時重新定義的一個function,而三個參數(shù)的時候,這個步驟就省略了。
總結(jié)及說明
這樣大家就對這個函數(shù)很明白了吧,也可以知道Ext.extend的繼承只會覆寫構(gòu)造函數(shù)prototype中的對象,使用的時候需要多加注意。
注意下面一段代碼:
if (superFnPrototype.constructor == Object.prototype.constructor) { superFnPrototype.constructor = superFn; } |
這段代碼我在改寫的Ext.extend中省略掉了。原因在于我嘗試了多次,發(fā)現(xiàn)參數(shù)為兩個參數(shù)的時候,只有第一個參數(shù)為Object對象或者為3個參數(shù)的時候,第二個參數(shù)為Object才會進(jìn)入此段代碼。
但是發(fā)現(xiàn)superFn也時function Object(){},在IE和FF下都是如此。那么我就不是很清楚這段代碼到底是什么用的了,若有清楚的,告訴一聲,哈。
上面的有幾段代碼源自網(wǎng)絡(luò),若有版權(quán)侵犯,非常抱歉。
先收藏了,既然博主能分析,我也先自己分析一遍,再來對照
小弟有些疑問,不知道是我理解錯誤,還是你的代碼敲錯了
“可以看到最簡單的繼承只做了兩件事情,一是把subFn的prototype設(shè)置為superFn的一個實例,然后設(shè)置subFn.prototype.constructor為subFn。”
如果設(shè)置subFn.prototype.constructor為superFn執(zhí)行的結(jié)果也是一樣的
這是為什么啊?
源代碼應(yīng)該是如下:
extend = function (){
// inline overrides
var inlineOverride = function(o){
for (var m in o) {
this[m] = o[m];
}
};
return function(superFn, overrides){
var subFn = function(){
superFn.apply(this, arguments);
};
var F = function(){
}, subFnPrototype, superFnPrototype = superFn.prototype;
F.prototype = superFnPrototype;
//注意下面兩句就是上面最簡單的繼承實現(xiàn)。
subFnPrototype = subFn.prototype = new F();
subFnPrototype.constructor = subFn;
//添加了superclass屬性指向superFn的Prototype
subFn.superclass = superFnPrototype;
//為subFn和subFnPrototype添加override函數(shù)
subFn.override = function(obj){
Ext.override(subFn, obj);
};
subFnPrototype.override = inlineOverride;
//覆蓋掉子類prototype中的屬性
Ext.override(subFn, overrides);
return subFn;
};
};
把function extend(){
......
}();
改為 extend = function(){
......
}();
樓主犯了很嚴(yán)重的錯誤。
你個傻逼
superFnPrototype.constructor = superFn;
}
這個的用法在于:b.superclass.constructor.call(this, arguments);
子類調(diào)用父類的構(gòu)造函數(shù)