我正在努力遵循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和父对象引用传递给每个子对象,或者可以尝试一些继承原则,看看我是否可以通过这种方式使用它。
我的问题如下:
为什么当我在另一个对象中定义的对象时,全局范围会“消失”?
是否有一种简单的方法可以从子对象内部访问该全局变量?
(也许是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;
}
答案 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
。