修复附加继承法中模拟重载的一缺陷

   在关于JavaScript继承的一系列讨论中,我详细的介绍和比较了四种继承方式,其中第四种"附加继承法"是一种对重载支持的最好的方法。并且也在我的实际开发中广泛的使用了,不过近来我发现在多层次的重载中,又出现了一个非常严重的bug修复附加继承法中模拟重载的一缺陷

    我们使用原来重载一文中的那个grandpa、father & son的示例:

修复附加继承法中模拟重载的一缺陷<html>
修复附加继承法中模拟重载的一缺陷<head>
修复附加继承法中模拟重载的一缺陷    <title>Researh Override in JavaScript OOP II</title>
修复附加继承法中模拟重载的一缺陷    <meta name="author" content="[email protected]博客园" />
修复附加继承法中模拟重载的一缺陷</head>
修复附加继承法中模拟重载的一缺陷<body>
修复附加继承法中模拟重载的一缺陷    <script language="javascript">修复附加继承法中模拟重载的一缺陷</script>
修复附加继承法中模拟重载的一缺陷    <script language="javascript">
修复附加继承法中模拟重载的一缺陷    
var g = new grandpa('Michael', 'William');
修复附加继承法中模拟重载的一缺陷    alert(g.getName()); 
修复附加继承法中模拟重载的一缺陷    
var f = new father('John', 'William');
修复附加继承法中模拟重载的一缺陷    alert(f.getName());
修复附加继承法中模拟重载的一缺陷    
var s = new son('Tom', 'William');
修复附加继承法中模拟重载的一缺陷    alert(s.getName());
修复附加继承法中模拟重载的一缺陷    
</script>
修复附加继承法中模拟重载的一缺陷</body>
修复附加继承法中模拟重载的一缺陷</html>

    // 在此参考:ExtendsCall方法

    运行结果是三个期望的alert窗口:
    No.1 alert:
    grandpa's name: Michael

    No.2 alert:
    grandpa's name: John
    father's name: John


    No.3 alert:
    grandpa's name: Tom
    father's name: Tom
    son's name: Tom


    这时如果我们修改上面的示例,把son对象的getName()方法注释掉,再次运行上面的代码,这时IE就Stack Overflow并立即crash掉了修复附加继承法中模拟重载的一缺陷。为什么会这样呢?

    在重载(续)一文中,我们详细的介绍了Call的实现原理,以及它是怎么样去查找base类中的方法的。而问题就出在这个查找方法所属的类实例的这个过程中,当son对象没有getName()方法时,我们调用s.getName()实际已经就是调用的father的getName()方法,这时在Call方法的检索循环中出现如下值:
    修复附加继承法中模拟重载的一缺陷

    由于我们没有给son类实现getName()方法,在调用s.getName()的时候,执行查找方法的所在类的时候。如果条件: thatBase[key] == arguments.callee.caller 为true,那么会出现:thatBase.getName和thatBase.base.getName实际是同一个方法的引用的情况,这是因为son没有实现getName(),thatBase.getName就是father的getName,然后thatBase.base实际是father的实例,所以thatBase.getName和thatBase.base.getName是同一个方法的引用。从上图的wathc 1窗口中也可以看到使用toString()输出的是同一个方法的内容。

    修复这个bug的方法需要继续读取继承树,即:target[key] == target.base[key] 时,让target = target.base;,修改后的源代码为:

修复附加继承法中模拟重载的一缺陷 /***********************************************************
修复附加继承法中模拟重载的一缺陷 CommonLab JScript Code Library
修复附加继承法中模拟重载的一缺陷
修复附加继承法中模拟重载的一缺陷 Author: lizhi[at]hit.edu.cn[http://www.cnblogs.com/birdshome/]
修复附加继承法中模拟重载的一缺陷 Company: http://www.u-soft.com.cn/
修复附加继承法中模拟重载的一缺陷 Copyright: U-Soft Co., Ltd. © All rights reserved.
修复附加继承法中模拟重载的一缺陷
修复附加继承法中模拟重载的一缺陷 Version: 1.2
修复附加继承法中模拟重载的一缺陷 Created: 2004.11.30 22:27
修复附加继承法中模拟重载的一缺陷 Updated: 2005.03.25 14:17
修复附加继承法中模拟重载的一缺陷
修复附加继承法中模拟重载的一缺陷 History:
修复附加继承法中模拟重载的一缺陷     8. Attach 'Call' method to Function. [2005.02.23]
修复附加继承法中模拟重载的一缺陷
修复附加继承法中模拟重载的一缺陷 Announce: You may use the code freely if this comment reserved.
修复附加继承法中模拟重载的一缺陷    
修复附加继承法中模拟重载的一缺陷 *********************************************************
*/
   Function.prototype.Call = function(that)
修复附加继承法中模拟重载的一缺陷{
修复附加继承法中模拟重载的一缺陷    if ( arguments.length < 1 )
修复附加继承法中模拟重载的一缺陷    {
修复附加继承法中模拟重载的一缺陷        throw new Error('The first parameter must be swapped object.');
修复附加继承法中模拟重载的一缺陷    }
修复附加继承法中模拟重载的一缺陷    var thatBase = that;
修复附加继承法中模拟重载的一缺陷    do
修复附加继承法中模拟重载的一缺陷    {
修复附加继承法中模拟重载的一缺陷        for ( var key in thatBase )
修复附加继承法中模拟重载的一缺陷        {
修复附加继承法中模拟重载的一缺陷            if ( thatBase[key] == arguments.callee.caller )
修复附加继承法中模拟重载的一缺陷            {
修复附加继承法中模拟重载的一缺陷                var target = thatBase;
修复附加继承法中模拟重载的一缺陷                while(target[key] == target.base[key])
修复附加继承法中模拟重载的一缺陷                {
修复附加继承法中模拟重载的一缺陷                    target = target.base;
修复附加继承法中模拟重载的一缺陷                }
修复附加继承法中模拟重载的一缺陷                if ( arguments.length == 1 )
修复附加继承法中模拟重载的一缺陷                {
修复附加继承法中模拟重载的一缺陷                    return target.base[key].call(that);
修复附加继承法中模拟重载的一缺陷                }
修复附加继承法中模拟重载的一缺陷                else
修复附加继承法中模拟重载的一缺陷                {
修复附加继承法中模拟重载的一缺陷                    var args = [];
修复附加继承法中模拟重载的一缺陷                    for ( var i=1 ; i < arguments.length ; ++i )
修复附加继承法中模拟重载的一缺陷                    {
修复附加继承法中模拟重载的一缺陷                        args.push(arguments[i]);
修复附加继承法中模拟重载的一缺陷                    }
修复附加继承法中模拟重载的一缺陷                    return target.base[key].apply(that, args);
修复附加继承法中模拟重载的一缺陷                }
修复附加继承法中模拟重载的一缺陷            }
修复附加继承法中模拟重载的一缺陷        }
修复附加继承法中模拟重载的一缺陷    }
修复附加继承法中模拟重载的一缺陷    while ( thatBase = thatBase.base )
修复附加继承法中模拟重载的一缺陷};

    这样一来,我们就可以通过重载调用任意级别基类的方法了修复附加继承法中模拟重载的一缺陷。 


本文转自博客园鸟食轩的博客,原文链接:http://www.cnblogs.com/birdshome/,如需转载请自行联系原博主。