为什么JavaScript中的子对象会失去全局作用域

Why does a child object in JavaScript lose the global scope?

本文关键字:失去 全局 作用域 对象 JavaScript 为什么      更新时间:2023-09-26

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

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

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

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

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

我在Stack Overflow上看到过其他帖子,它们通过显式地将父引用转发到子对象中,为父/子对象通信提供了解决方案,但这并不是我真正想要的。我希望能够从任何一点访问根,如果我落后三到四级,我不想再处理追踪链的问题。

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

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

我的问题如下:

  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>");
}

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

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

问题是您正在调用。。。

var parent = null;
$(document).ready(function() {
    parent = new Foo();
    // ...
});

它调用CCD_ 1。。。

this.log = new Logger("output");
this.log.write("Foo constructor");
this.x = 1;
this.child = new ChildFoo;

其调用ChildFoo、尝试访问parent。。。

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

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