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

Gra*_*ham 0 javascript oop

我正在努力遵循Douglas Crockford的建议,来自"JavaScript:The Good Parts"和他的网站:

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

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

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

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

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

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

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

我的问题如下:

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

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

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

我的示例代码如下(这里加载到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>");
}
Run Code Online (Sandbox Code Playgroud)

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

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

小智 5

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

var parent = null;

$(document).ready(function() {

    parent = new Foo();

    // ...
});
Run Code Online (Sandbox Code Playgroud)

......哪个叫Foo......

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

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

this.x = 1;

this.child = new ChildFoo;
Run Code Online (Sandbox Code Playgroud)

...哪个叫ChildFoo,试图访问parent......

parent.log.write("Child constructor");
Run Code Online (Sandbox Code Playgroud)

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

  • +1用于破译他实际想要/需要的东西 (2认同)