extjs extends

Ext中实现类的继承

Js代码
  1. extend (Object subclass,Object superclass,[Object overrides] : Object)


第一个参数:子类
第二个参数:父类
第三个参数:要覆盖的属性。
这里需要强调一下,子类继承下来的是父类中通过superclass.prototype方式定义的属性(包括用此方法定义的函数),而不继承superclass中的定义的属性和方法,如果子类中的方法名与父类中相同则会覆盖。例子

父类

Js代码
  1. BaseClass = function() {
  2. f1 = function() {
  3. alert("f1 in base");
  4. },
  5. f2 = function() {
  6. alert("f2 in base");
  7. }
  8. }
  9. BaseClass.prototype = {
  10. f3 : function() {
  11. alert("f3 in base");
  12. },
  13. f4 : function() {
  14. alert("f4 in base");
  15. }
  16. };


子类

Js代码
  1. ChildClass = function() {
  2. }
  3. // 继承
  4. Ext.extend(ChildClass, BaseClass, {
  5. f1 : function() {
  6. alert("f1 in child");
  7. },
  8. f3 : function() {
  9. alert("f3 in child");
  10. }
  11. });


实例化

Js代码
  1. var b = new ChildClass();
  2. b.f1();// 调用子类中的实现
  3. //b.f2();// 会报错,因为子类中没有该方法,并且父类中定义的f2是内部变量,作用域只有在内部可见(闭包)
  4. b.f3();// 继承并覆盖,调用子类的中的实现
  5. b.f4();// 继承,调用父类的中的实现

补充:通过对 JavaScript 的原型继承的了解,可以知道,实例变量的优先级是高于 prototype 的,参见我之前写的文章javascript中静态方法、实例方法、内部方法和原型的一点见解 又如以下例子:
父类

Js代码
  1. BaseClass = function() {
  2. this.f1 = function() {
  3. alert("f1 in base");
  4. },
  5. this.f2 = function() {
  6. alert("f2 in base");
  7. }
  8. }


子类

Js代码
  1. ChildClass = function() {
  2. ChildClass.superclass.constructor.call( this );
  3. }
  4. // 继承
  5. Ext.extend(ChildClass, BaseClass, {
  6. f1 : function() {
  7. alert("f1 in child");
  8. },
  9. f3 : function() {
  10. alert("f3 in child");
  11. }
  12. });


实例化

Js代码
  1. var b = new ChildClass();
  2. b.f1();// 调用父类中的实现,注意不会调用子类中的实现
  3. b.f2();// 调用父类中的实现
  4. b.f3();// 调用子类中的实现

分析:在 ChildClass.superclass.constructor.call(this); 这句上, BaseClass 的 f1 成了 ChildClass 的变量,而不是 ChildClass.prototype 。由于实例变量的优先级是高于 prototype 的,所以上面的这个代码是达不到 override 的功能的。


了解了以上知识,下面讲解一下extend的实现,先看最简单的继承,实现原理,1、将子类的原型prototype设置为父类的一个实例,也就是说把父类的实例赋值给子类的prototype(这样子类就有了父类原型的所有成员),2、重新将子类原型的构造器设置为子类自己,也就是把子类赋值给子类原型的构造器。
以下代码把 subFn 的 prototype 设置为 superFn 的一个实例,然后设置 subFn.prototype.constructor 为 subFn。

Js代码
  1. function Extend(subFn, superFn) {
  2. subFn.prototype = new superFn();
  3. subFn.prototype.constructor = subFn;
  4. }
  5. //父类
  6. function Animal() {
  7. this.say1 = function() {
  8. alert("Animal");
  9. }
  10. }
  11. //子类
  12. function Tiger() {
  13. this.say2 = function() {
  14. alert("Tiger");
  15. }
  16. }
  17. //继承应用
  18. Extend(Tiger, Animal);
  19. var tiger = new Tiger();
  20. tiger.say1();// "Animal"
  21. tiger.say2();// "Tiger"

可以看到最简单的继承只做了两件事情,一是把 subFn 的 prototype 设置为 superFn 的一个实例,然后设置 subFn . prototype . constructor 为 subFn 。


Ext.extend 的代码


Ext.extend 函数中用到了 Ext.override ,这个函数把第二个参数中的所有对象复制到第一个对象的 prototype 中。首先贴上 Ext.override 函数的代码:

Js代码
  1. /**
  2. * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
  3. * Usage:<pre><code>
  4. Ext.override(MyClass, {
  5. newMethod1: function(){
  6. // etc.
  7. },
  8. newMethod2: function(foo){
  9. // etc.
  10. }
  11. });
  12. </code></pre>
  13. * @param {Object} origclass The class to override
  14. * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
  15. * containing one or more methods.
  16. * @method override
  17. */
  18. override : function(origclass, overrides){
  19. if(overrides){
  20. var p = origclass.prototype;
  21. Ext.apply(p, overrides);
  22. if(Ext.isIE && overrides.hasOwnProperty(‘toString‘)){
  23. p.toString = overrides.toString;
  24. }
  25. }
  26. }

以下是 Ext.extend的代码

Js代码
  1. /**
  2. * 继承,并由传递的值决定是否覆盖原对象的属性
  3. * 返回的对象中也增加了 override() 函数,用于覆盖实例的成员
  4. * @param { Object } subclass 子类,用于继承(该类继承了父类所有属性,并最终返回该对象)
  5. * @param { Object } superclass 父类,被继承
  6. * @param { Object } overrides (该参数可选) 一个对象,将它本身携带的属性对子类进行覆盖
  7. * @method extend
  8. */
  9. extend : function(){
  10. // inline overrides
  11. var io = function(o){
  12. for(var m in o){
  13. this[m] = o[m];
  14. }
  15. };
  16. var oc = Object.prototype.constructor;
  17. //匿名函数实现
  18. //三个参数sb、sp、overrides分别代表subClass(子类)、superClass(父类)及覆盖子类的配置参数
  19. return function(sb, sp, overrides){
  20. if(typeof sp == ‘object‘){//传递两个参数时superClass, overrides
  21. overrides = sp;
  22. sp = sb;
  23. sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);};
  24. }
  25. var F = function(){},//定义一空函数,用来赋给其对象时清空该对象
  26. sbp,
  27. spp = sp.prototype;
  28. F.prototype = spp;
  29. // 注意下面两句就是JavaScript中最简单的继承实现。
  30. sbp = sb.prototype = new F();//清空
  31. sbp.constructor=sb;
  32. // 添加了 superclass 属性指向 superclass 的 prototype
  33. sb.superclass=spp;
  34. if(spp.constructor == oc){
  35. spp.constructor=sp;
  36. }
  37. // 为 subClass 和 subClassPrototype 添加 override 函数
  38. sb.override = function(o){
  39. Ext.override(sb, o);
  40. };
  41. sbp.superclass = sbp.supr = (function(){
  42. return spp;
  43. });
  44. sbp.override = io;
  45. // 覆盖掉子类 prototype 中的属性
  46. Ext.override(sb, overrides);
  47. //为子类加上类方法:extend
  48. sb.extend = function(o){return Ext.extend(sb, o);};
  49. return sb;
  50. };
  51. }(),

代码中进行了太多的简写,看起来不是特别方便,把代码中的简写补全,代码如下:

Js代码
  1. extend : function(){
  2. // inline overrides
  3. var inlineOverride = function(o){
  4. for(var m in o){
  5. this[m] = o[m];
  6. }
  7. };
  8. var oc = Object.prototype.constructor;
  9. return function(subFn, superFn, overrides){
  10. if(typeof superFn == ‘object‘){
  11. // 如果 superFn 也是对象的话(一般来说 superFn 这里放的是父类的构造函数),那么第三个参数 overrides 参数相当于被忽略掉
  12. overrides = superFn;
  13. superFn = subFn;
  14. //重新定义了函数 subFn
  15. subFn = overrides.constructor != oc ? overrides.constructor : function(){superFn.apply(this, arguments);};
  16. }
  17. var F = function(){},
  18. subFnPrototype,
  19. superFnPrototype = superFn.prototype;
  20. F.prototype = superFnPrototype;
  21. subFnPrototype = subFn.prototype = new F();
  22. subFnPrototype.constructor=subFn;
  23. subFn.superclass=superFnPrototype;
  24. if(superFnPrototype.constructor == oc){
  25. superFnPrototype.constructor=superFn;
  26. }
  27. subFn.override = function(o){
  28. Ext.override(subFn, o);
  29. };
  30. subFnPrototype.superclass = subFnPrototype.supr = (function(){
  31. return superFnPrototype;
  32. });
  33. subFnPrototype.override = inlineOverride;
  34. Ext.override(subFn, overrides);
  35. subFn.extend = function(o){return Ext.extend(subFn, o);};
  36. return subFn;
  37. };
  38. }()

代码中糅合了传两个参数和三个参数的实现,理解起来不容易明白,我们可以把代码拆分为两个参数和三个参数的实现,如下两个参数的 Ext.extend 代码

Js代码
  1. function extend() {
  2. // inline overrides
  3. var inlineOverride = function(o) {
  4. for (var m in o) {
  5. this[m] = o[m];
  6. }
  7. };
  8. return function(superFn, overrides) {
  9. // 定义返回的子类
  10. var subFn=overrides.constructor != Object.prototype.constructor ? overrides.constructor : function(){superFn.apply(this, arguments);};
  11. //以下为中间变量,或叫过程变量
  12. var F = function() {
  13. }, subFnPrototype, superFnPrototype = superFn.prototype;
  14. F.prototype = superFnPrototype;//F中含有了所有 superFn.prototype 中的功能
  15. // 注意下面两句就是JavaScript中最简单的继承实现。
  16. subFnPrototype = subFn.prototype = new F();
  17. subFnPrototype.constructor = subFn;
  18. //改变父类实例对象中的constructor,使其指向自身的构建函数
  19. if(superFnPrototype.constructor == oc){
  20. superFnPrototype.constructor=superFn;
  21. }
  22. // 添加了 superclass 属性指向 superFn 的 prototype
  23. subFn.superclass = superFnPrototype;
  24. // 为 subFn 和 subFnPrototype 添加 override 函数
  25. subFn.override = function(obj) {
  26. Ext.override(subFn, obj);
  27. };
  28. subFnPrototype.override = inlineOverride;
  29. // 覆盖掉子类 prototype 中的属性
  30. Ext.override(subFn, overrides);
  31. //为子类加上类方法:extend
  32. subFn.extend=function(o){
  33. Ext.extend(subFn,o);
  34. }
  35. return subFn;
  36. };
  37. };

从注释中可以看到,做的工作很简单,只是定义一个 subFn 函数,这个函数中会调用 superFn 函数。定义了 subFn 以后,就使用上面的最简单的继承方式实现继承。然后为 subFn 和 subFn 的 prototype 添加了一个 override 函数。最后的 Ext.override(subFn, overrides); 把 overrides 中的函数写入 subFn 的 prototype 中。

以下是传两个参数的简单例子

Js代码
  1. var BaseClass = function(){};
  2. BaseClass.prototype = {
  3. method1 : function(){
  4. alert(‘father class‘);
  5. }
  6. };
  7. //两个参数的继承
  8. var subClass = Ext.extend(BaseClass,{
  9. method2 : function(){
  10. alert(‘sub class‘);
  11. }
  12. });
  13. var sub = new subClass();
  14. sub.method1();
  15. sub.method2();

三个参数的 Ext.extend 代码

Js代码
  1. function extend() {
  2. // inline overrides
  3. var inlineOverride = function(o) {
  4. for (var m in o) {
  5. this[m] = o[m];
  6. }
  7. };
  8. return function(subFn, superFn, overrides) {
  9. // 以下为中间变量,或叫过程变量
  10. var F = function() {
  11. }, subFnPrototype, superFnPrototype = superFn.prototype;
  12. F.prototype = superFnPrototype;// F中含有了所有 superFn.prototype 中的功能
  13. // 注意下面两句就是JavaScript中最简单的继承实现。
  14. subFnPrototype = subFn.prototype = new F();
  15. subFnPrototype.constructor = subFn;
  16. // 添加了 superclass 属性指向 superFn 的 Prototype
  17. subFn.superclass = superFnPrototype;
  18. //改变父类实例对象中的constructor,使其指向自身的构建函数
  19. if(superFnPrototype.constructor == oc){
  20. superFnPrototype.constructor=superFn;
  21. }
  22. // 为 subFn 和 subFnPrototype 添加 override 函数
  23. subFn.override = function(obj) {
  24. Ext.override(subFn, obj);
  25. };
  26. subFnPrototype.override = inlineOverride;
  27. // 覆盖掉子类 prototype 中的属性
  28. Ext.override(subFn, overrides);
  29. // 为子类加上类方法:extend
  30. subFn.extend = function(o) {
  31. Ext.extend(subFn, o);
  32. }
  33. return subFn;
  34. };
  35. };


过程与两个参数的时候相差无几,只是两个参数的时候, subFn 时重新定义的一个 function ,而三个参数的时候,这个步骤就省略了。

以下是传三个参数的例子

Js代码
  1. var BaseClass = function(){};
  2. BaseClass.prototype = {
  3. method1 : function(){
  4. alert(‘father class‘);
  5. }
  6. };
  7. //三个参数的继承
  8. var subClass = function(){}
  9. Ext.extend(subClass,BaseClass,{
  10. method2 : function(){
  11. alert(‘sub class‘);
  12. }
  13. });
  14. var sub = new subClass();
  15. sub.method1();
  16. sub.method2();


这样大家就对这个函数很明白了吧,也可以知道 Ext.extend 的继承只会覆写构造函数 prototype 中的对象,使用的时候需要多加注意。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。