为什么JavaScript中的子对象失去了全局范围?

时间:2012-01-17 23:03:56

标签: javascript oop

我正在努力遵循Douglas Crockford的建议,来自“JavaScript:The Good Parts”及其网站:

  

应尽量减少全局变量的使用。隐含的全局变量   绝不应该使用。

为此,我定义了一个“根”对象,它充当所有其他对象的容器,现在所有内容都被安排到共享功能的逻辑层次结构中。

我难倒的地方是子对象似乎失去了全局对象的范围。我能想到的最好的例子是我的记录器,我想将其全局定义为 root.log ,并在其他地方重复使用。

但是,当我尝试访问子对象中的 root.log 时,我的代码失败,因为它无法看到对 的任何引用root 对象了。我将子对象移动到全局范围内,它再次看到一切正常。

我已经看到Stack Overflow上的其他帖子通过将父引用向前传递给子进程来为父/子对象通信提供解决方案,但这并不是我在这之后所做的。我希望能够从任何一点访问root,如果我有三到四个级别,我不想处理追踪链。

这可能是一个明确的例子,如果我在我的实用程序层次结构深处,我想记录一条消息。假设我在 root.util.array.getPositionInArray() ,我已将父值传递给每个子对象。我不想打电话给 parent.parent.parent.log.write ,我只想对 root进行一次简单的调用。 log.write

我可以在创建每个子对象时将root和父对象引用传递给每个子对象,或者可以尝试一些继承原则,看看我是否可以通过这种方式使用它。

我的问题如下:

  1. 为什么当我在另一个对象中定义的对象时,全局范围会“消失”?

  2. 是否有一种简单的方法可以从子对象内部访问该全局变量?

  3. (也许是2的重复)处理此问题的推荐方法是什么?

  4. 我的示例代码如下(此处已加载到jsfiddle

    // declare root object as global variable
    var root = null;
    
    $(document).ready(function() {
    
        // instantiate root
        root = new Foo();
    
        // uncomment to instantiate child separately
        // child = new ChildFoo();
    
        // write to log from outside parent (shows scope is global)
        root.log.write(root.x)
        root.log.write(root.child.x);
    
    
    });
    
    function Foo() {
    
        // instantiate logger as child of parent
        this.log = new Logger("output");
    
        // write a quick message
        this.log.write("Foo constructor");
    
        // set value of x
        this.x = 1;
    
        // instantiate child object
        this.child = new ChildFoo;
    
    }
    
    // child object definition
    function ChildFoo() {
    
        // why is root.log == null here?
        root.log.write("Child constructor");
    
        // this reference to parent also fails
        // this.x = 10 * root.x;
    
        this.x = 10;
    
    }
    
    // log object definition
    function Logger(container) {
    
        // store reference to dom container
        this.container = container;
    
    }
    
    // method to write message to dom
    Logger.prototype.write = function(message) {
        $("#" + this.container).append("[" + new Date() + "] " + message + "<br>");
    }
    

    我已经能够通过将以下部分添加到Foo对象定义的顶部来使其工作。这会立即提供对根对象的全局对象引用,并且还实现Singleton模式以确保只有一个根对象。 jsfiddle已经完全更新了。

    if(root != null){
        root.log.write("Root object already instantiated");
        return root;
    } else {
        root = this;
    }
    

1 个答案:

答案 0 :(得分:5)

问题是你在打电话......

var parent = null;

$(document).ready(function() {

    parent = new Foo();

    // ...
});

...调用Foo ...

this.log = new Logger("output");

this.log.write("Foo constructor");

this.x = 1;

this.child = new ChildFoo;

...调用ChildFoo,试图访问parent ...

parent.log.write("Child constructor");

这是一次性调用,因此在您尝试访问new Foo之前,原始parent尚未完成,因此parent仍为null