extend

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 下都是如此。那么我就不是很清楚这段代码到底是什么用的了,若有清楚的,告诉一声,哈。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/kinglino520/archive/2009/06/24/4294686.aspx

你可能感兴趣的:(JavaScript,ext,prototype,F#,IE)