代码之家  ›  专栏  ›  技术社区  ›  Mike Hofer

令人费解的JavaScript继承行为

  •  2
  • Mike Hofer  · 技术社区  · 14 年前
    <disclaimer> 
    What follows is the fruits of a thought experiment. What I'm doing 
    isn't the issue; the symptoms are. Thank you.
    </disclaimer>
    

    我终于把注意力集中在JavaScript中的构造函数、原型和原型继承上了。但是下面的示例中的somethingspectular方法让我很烦:

    function FinalClass() {    
        return {
            FinalFunction : function() { return "FinalFunction"; },
            TypeName : "FinalClass",
            SomethingSpectacular : function() { 
                return FinalClass.prototype.SubFunction.call(this);
            }
        }
    }
    FinalClass.prototype = new SubClass();
    FinalClass.constructor = FinalClass;
    
    var f = new FinalClass();
    

    1. JavaScript语言 显然地 对方法的扫描方式与对属性的扫描方式不同。也就是说, f.SubFunction()
    2. 为了在一个原型上获得一个方法,你必须每次至少经历3个点操作。最终类点原型点子函数点调用。你明白了。

    所以我的想法是,如果我写一个版本的 inherits 它将存根函数插入到子类中,子类为您委派回原型。例如,它将自动创建以下函数并将其添加到 FinalClass

    function SubFunction() { SubClass.prototype.SubFunction.call(this); }
    

    现在,我已经把一切都安排好了。这个 继承 Object.prototype Function.prototype Function 作为唯一的论据。这是基类。子类是通过分析 Object.prototype.inherits.caller .

    prototype constructor return 声明。

    现在,我可以一步一步地完成所有这些代码,它工作得非常出色,直到我实例化为止 实例 子类的。那是事情变得不稳定的时候。以下是我使用Visual Studio 2008(SP1)和Internet Explorer 8观察到的内容:

    1. 在实例化之前, BaseClass 不公开任何公共方法。这是意料之中的。通过类构造函数的 语句在实例化之前不会出现。我不介意。
    2. 在实例化之前, SubClass 显示来自的方法 基类 . 这正是我所期望的。
    3. 基类 ,它拥有我所期望的所有成员。它有自己的特点 typeName BaseFunction 方法。
    4. 子类 返回 声明。基类中没有成员。在inherits方法中完成的将基类方法映射到子类的所有工作似乎都丢失了。

    这里对我来说最大的谜团是我在执行继承时添加到子类的方法的消失。在它的执行过程中,我可以清楚地看到子类正在被修改,基类的函数正在被传播。但当我创建一个子类时,这些信息就不再存在了。

    我假设这与构造器、事件顺序或其他我根本看不到的东西有关。

    最后一句话:

    代码

    sti.objects.inherits = function inherits(baseClass) {
    
        var subClass = sti.objects.inherits.caller;
    
        var baseClassName = sti.objects.getTypeName(baseClass);
        var methods = sti.objects.getMethods(baseClass); 
    
        if(!sti.objects.isDefined(baseClass.typeName))
            baseClass.typeName = baseClassName;
    
        var subClass = sti.objects.inherits.caller;
        var subClassName = sti.objects.getTypeName(subClass);
    
        var temp = function() {};
        temp.prototype = new baseClass();
    
        subClass.prototype = temp.prototype;
        subClass.constructor = subClass;
        subClass.typeName = subClassName;
        subClass.baseClass = baseClass.prototype;   //  Shortcut to the prototype's methods
        subClass.base = baseClass;  //  Cache the constructor
    
        for(var index = 0; index < methods.items.length; index++) {
            var resource = methods.items[index].getFunction();
            var methodName = methods.items[index].getName();
            if(methodName != "" && ! sti.objects.isDefined(subClass[methodName])) {
                var method = sti.objects.createOverride(baseClassName, resource);
                subClass[methodName] = method;
                if(typeof subClass.prototype[methodName] == "undefined") {
                    subClass.prototype[methodName] = method;
                }
            }
        }
    }
    
    Object.prototype.inherits = sti.objects.inherits;
    Function.prototype.inherits = sti.objects.inherits;
    
    function BaseClass() {
        return { 
            A : function A() {return "A";} 
        };
    }
    
    
    function SubClass() {
        inherits(BaseClass);
    
        return {
            B : function B() { return "B"; }
        }    
    }
    
    var b = new BaseClass();
    var s = new SubClass();
    
    1 回复  |  直到 14 年前
        1
  •  4
  •   Toby    14 年前

    你的构造函数不是构造函数。当您使用new关键字时,Javascript创建新对象并期望您的构造函数用成员等填充它。您的构造函数返回另一个新对象,与与构造函数用法关联的对象无关,因此原型无法工作。

    将构造函数更改为

    function FinalClass() {
        this.FinalFunction = function() { return "FinalFunction"; };
        this.TypeName = "FinalClass";
        this.SomethingSpectacular = function() { 
            return FinalClass.prototype.SubFunction.call(this);
        };
    }