Почему дочерний объект в JavaScript теряет глобальную область видимости? - PullRequest
0 голосов
/ 18 января 2012

Я стараюсь следовать совету Дугласа Крокфорда из "JavaScript: Хорошие части" и его веб-сайта:

Использование глобальных переменных должно быть сведено к минимуму.Подразумеваемые глобальные переменные никогда не должны использоваться.

Для этого я определил один «корневой» объект, который действует как контейнер для всех других объектов, и теперь все организовано в логическую иерархию общихфункциональность.

Где я озадачен, так это то, как дочерние объекты, похоже, теряют область видимости глобального объекта.Лучший пример, который я могу привести здесь, - это мой регистратор, который я хочу определить глобально как root.log и использовать его повсюду.

Однако, когда япопробуйте получить доступ к root.log внутри дочернего объекта, мой код завершается ошибкой, потому что он не видит никакой ссылки на объект root Больше.Я перемещаю дочерний объект в глобальную область видимости, и он снова видит все нормально.

Я видел другие публикации в переполнении стека, которые предоставляют решения для связи родительского / дочернего объекта путем явной передачи родительской ссылки в дочерний объект, но это не то, что я здесь после.Я хочу иметь доступ к корню из любой точки, и если я на три или четыре уровня ниже, мне не нужно иметь дело с отслеживанием обратной цепочки.

Явный пример этого можетбыть, если я в глубине своей служебной иерархии, и я хочу записать сообщение.Допустим, я нахожусь на root.util.array.getPositionInArray () , и я передал родительское значение в каждый подобъект.Я не хочу вызывать parent.parent.parent.log.write , я просто хочу сделать один простой вызов root.log.напишите .

Я мог бы передать ссылки на корневой и родительский объекты в каждый подобъект по мере их создания, или, возможно, поэкспериментировать с некоторыми принципами наследования и посмотреть, смогу ли я заставить его работать таким образом.

У меня следующие вопросы:

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

1 Ответ

5 голосов
/ 18 января 2012

Проблема в том, что вы звоните ...

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...