Ext.extend用法以及代码解读
概述
Ext.extend是Ext的继承机制,这个函数的代码相当难懂。要明白这个函数的代码,首先要知道这个函数如何使用。
使用方式
使用示例
假设有个function名为SuperClass,要实现一个子类,名为MyClass。下面的两种方式都可以实现这个功能。
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("f1 in base"); }
this.f2 = function() { alert("f2 in base"); } }
ChildClass = function() { ChildClass.superclass.constructor.call(this); }
Ext.extend(ChildClass, BaseClass, { f1: function() { alert("f1 in child"); },
f3: function() { alert("f3 in child"); } });
var b = new ChildClass(); b.f1(); b.f2(); b.f3(); |
可以去执行一下,可以发现f1的执行结果仍然是"f1 in base"。并没有真正的达到override的效果。
Ext.extend puts the properties specified in the 3rd argument into the subclass's prototype |
也就是说:第三个参数里面的函数被放置在了子类的prototype中。
而在ChildClass.superclass.constructor.call(this);这句上,BaseClass的f1成了ChildClass的变量,而不是ChildClass.prototype。通过对JavaScript的原型继承的了解,可以知道,实例变量的优先级是高于prototype的,所以上面的这个代码是达不到override的功能的。
修改的方式如下:
BaseClass = function() { };
BaseClass.prototype = { f1: function() { alert("f1 in base"); } }; |
代码解读
JavaScript中的继承实现
先了解一下最简单的继承是如何实现的:
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设置为superFn的一个实例,然后设置subFn.prototype.constructor为subFn。
Ext.extend的代码
Ext.extend函数中用到了Ext.override,这个函数把第二个参数中的所有对象复制到第一个对象的prototype中。首先贴上Ext.override函数的代码:
Ext.override = function(origclass, overrides){ if(overrides){ var p = origclass.prototype; for(var method in overrides){ p[method] = overrides[method]; } } } |
然后贴上Ext.extend的代码:
/** * 继承,并由传递的值决定是否覆盖原对象的属性 * 返回的对象中也增加了override()函数,用于覆盖实例的成员 * @param {Object} subclass 子类,用于继承(该类继承了父类所有属性,并最终返回该对象) * @param {Object} superclass 父类,被继承 * @param {Object} overrides (该参数可选) 一个对象,将它本身携带的属性对子类进行覆盖 * @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 |