3

所以我在一些 JavaScript 代码中有一个错误,这让我有些发疯。我一直在尝试模仿 JavaScript 中的经典继承(我知道,我知道,我在这里读到的一半帖子都说不要将 JavaScript 扭曲成这样的框架,但我的应用程序需要有一个映射到我的服务器端 php 代码的继承结构)。大多数情况下,看起来一切正常。这是我用来扩展类的函数:

Function.prototype.inheritsFrom = function(parentClass) {
//:: Ordinary Classes
if (parentClass.constructor == Function) {
    this.prototype             = new parentClass();
    this.prototype.constructor = this;
    this.prototype.parent      = parentClass.prototype;

//:: Abstract Classes
} else {
    this.prototype             = parentClass;
    this.prototype.constructor = this;
    this.prototype.parent      = parentClass;
}
return this;
}

不是我自己的创作,我在网上找到的,但效果很好。我唯一需要添加的是一个“超级”函数来搜索原型链的父方法;上述代码中的父结构并非在所有情况下都有效。

无论如何,由于我一直在解决我的代码中的一些错误,我发现我的基“类”中的一种方法是访问/修改从其所有子类创建的所有实例的相同变量。换句话说,每当一个实例修改这个应该是其对象上下文本地的变量时,它实际上修改了一些在所有实例之间共享的变量。这是基类:

    function DataManipulatorControl() {
    //|| Private Members ||//

    var that = this;



    //|| Properties ||//

    //|| Root ID
    this.rootID = function(value) {
        if (value !== undefined) {
            if (_root_id !== null) {
                alert('@ ' + _root_id);
                $('#' + _root_id).prop('js_object', null);
            }
            _root_id = value;
            $('#' + _root_id).prop('js_object', this);
        }
        return _root_id;
    }
    var _root_id = null;

    // other properties/methods
}



//|| Class: DataManipulatorContainerControl
function DataManipulatorContainerControl() {
    //|| Private Members ||//

    var that = this;


    // subclass properties/methods
}
DataManipulatorContainerControl.inheritsFrom(DataManipulatorControl);

正如我所提到的,当我创建这些原型的新实例时,我发现更改一个实例的 rootID 会改变所有实例。我的第一个想法是我在某处忘记了“var”,而我的函数正在访问全局上下文。不过,情况似乎并非如此,所以我的下一个想法是它使用了原型本地的变量。不过,这对我来说也没有多大意义,因为原型构造函数调用的本地变量不应该在它之外访问,除非由已经在范围内的方法访问。当然,rootID() 函数确实在范围内,但我的印象是它将使用调用对象的对象上下文而不是原型来运行。

所以,我很困惑。任何可以在这个问题上阐明的观点都会唤起我们的感激之情。

编辑: PRB 提供的文章描述了一个干净地解决这个问题的解决方案 - 主要是。文章指出,您还需要从子类构造函数中调用父类的构造函数以正确初始化所有内容。结果,所有的方法都是新创建的,它们自己的父类局部变量版本都在闭包中。

这种方法似乎确实存在一个缺点(除了在每个实例中复制函数的效率问题)。如果一个人试图从原型链中调用“覆盖”的函数来尝试超级功能,那么这个问题将再次出现。和以前一样,原型是单个对象的实例,尝试调用它们的函数版本将导致它们尝试访问其实例的局部变量。

仍然是我见过的最好的解决方案,除了公开所有数据:-)。

4

2 回答 2

2

使用这条线可能是问题所在:

this.prototype             = new parentClass();

这意味着该函数的所有实例共享同一个由 parentClass() 定义的内存 blob。这就是为什么当您将值更改为一个时,它会影响所有这些值。

于 2012-11-17T22:28:20.427 回答
0

好的,所以我在吃晚饭时一直在考虑它,我想我可能对正在发生的事情有所了解。我认为我混淆了由于对象上下文的变化而对函数可用的变量,以及由于闭包而对函数可用的变量。

正如 PRB 指出的那样,我的 rootID() 函数总是从实例化的原型访问内存块。_root_id 被创建为我的基类的构造函数的本地变量,因此当该基类被实例化为原型时,所有使用原型函数的子类将因此读取/写入构造函数中创建的一个变量.

因此,虽然这是创建原型的有效方法,但使用构造函数本地变量隐藏对象的数据在子类中将无法正常工作。相反,我需要读取/写入“this”中的变量,以便它随着对象上下文的变化而变化。如果有人知道更好的方法来处理这个问题 - 一种遵守数据隐藏的方法,请随时发表评论;与我一起工作的许多开发人员都对直接访问数据成员而不是通过访问器感到不安。使代码难以维护:-/。

无论如何,感谢 PRB 的澄清!〜内特

于 2012-11-17T23:15:58.403 回答