extend (Object subclass,Object superclass,[Object overrides] : Object
第一个参数:子类
第二个参数:父类
第三个参数:要覆盖的属性。
这里需要强调一下,子类继承下来的是父类中通过superclass.prototype方式定义的属性(包括用此方法定义的函数)。
使用方式
使用示例
假设有个 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 ); return sb ; }; }(); |
代码中进行了太多的简写,看起来不是特别方便,把代码中的简写补全,代码如下:
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 这里放的是父类的构造函数),那么第三个参数 overrides 参数相当于被忽略掉 overrides = superFn ; superFn = subFn ; //subFn 重新定义了函数 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 ; }; }; |
补全以后也不是特别容易明白,那么我们就把这个代码分开,分为 2 个参数和 3 个参数。
两个参数的 Ext.extend 代码
首先把代码改写成两个参数的。
// 两个参数的时候的代码,注意第二个参数必须为 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 ; // 注意下面两句就是上面最简单的继承实现。 subFnPrototype = subFn . prototype = new F (); subFnPrototype . constructor = subFn ; // 添加了 superclass 属性指向 superFn 的 Prototype subFn . superclass = superFnPrototype ;
// 为 subFn 和 subFnPrototype 添加 override 函数 subFn . override = function ( obj ){ Ext . override ( subFn , obj ); }; subFnPrototype . override = inlineOverride ;
// 覆盖掉子类 prototype 中的属性 Ext . override ( subFn , overrides ); return subFn ; }; }; |
从注释中可以看到,做的工作很简单,只是定义一个 subFn 函数,这个函数中会调用 superFn 函数。定义了 subFn 以后,就使用上面的最简单的继承方式实现继承。然后为 subFn 和 subFn 的 prototype 添加了一个 override 函数。最后的 Ext.override(subFn, overrides); 把 overrides 中的函数写入 subFn 的 prototype 中。
三个参数的 Ext.extend 代码
下面我们把函数改写为只处理 3 个参数的,改写后的代码如下:
// 三个参数时的代码 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 ; // 注意下面两句就是上面最简单的继承实现。 subFnPrototype = subFn . prototype = new F (); subFnPrototype . constructor = subFn ; // 添加了 superclass 属性指向 superFn 的 Prototype subFn . superclass = superFnPrototype ;
// 为 subFn 和 subFnPrototype 添加 override 函数 subFn . override = function ( obj ){ Ext . override ( subFn , obj ); }; subFnPrototype . override = inlineOverride ;
// 覆盖掉子类 prototype 中的属性 Ext . override ( subFn , overrides ); return subFn ; }; };
|
过程与两个参数的时候相差无几,只是两个参数的时候, subFn 时重新定义的一个 function ,而三个参数的时候,这个步骤就省略了。
总结及说明
这样大家就对这个函数很明白了吧,也可以知道 Ext.extend 的继承只会覆写构造函数 prototype 中的对象,使用的时候需要多加注意。
注意下面一段代码:
if ( superFnPrototype . constructor == Object . prototype . constructor ) { superFnPrototype . constructor = superFn ; } |
这段代码我在改写的 Ext.extend 中省略掉了。原因在于我尝试了多次,发现参数为两个参数的时候,只有第一个参数为 Object 对象或者为 3 个参数的时候,第二个参数为 Object 才会进入此段代码。
但是发现 superFn 也时 function Object(){} ,在 IE 和 FF 下都是如此。那么我就不是很清楚这段代码到底是什么用的了,若有清楚的,告诉一声,哈。
上面的有几段代码源自网络,若有版权侵犯,非常抱歉。