Переменная Область в Модульном Javascript - PullRequest
4 голосов
/ 04 ноября 2010

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

В последнее время я начал писать свой код JavaScript в модульном стиле, и у меня возник вопрос относительно того, как переменная модуляscope работает.

Следующий код дает мне противоречивый ответ.

У меня есть модуль с именем Base, который объявляет две строки и массив.Он также имеет функцию fetchData, которая использует ярлык jQuery getJSON для установки этих переменных с данными сервера.К сожалению, когда я спрашиваю у Base1 string1 или string2, я получаю неопределенный.Я понимаю, что это, вероятно, связано с тем, что я установил их значения двумя функциями глубоко (внутри обратного вызова AJAX и внутри fetchData), и область видимости ограничивает его от просмотра Base.string1 и Base.string2.

Однако, когда я смотрю на Base.array1 снаружи модуля, он настроен на соответствующие данные, которые я извлек с сервера, даже если он установлен в той же области, что и строки.

Вот код:

namespace.Base = (function(){
    var string1, string2, array1 = [];
    function fetchData(){
        $.getJSON('backendScript.php', function(data){
            string1 = data.string1;
            string2 = data.string2;
                arrayCount = data.arr.length;
                for(var i = 0; i<arrayCount; i++){
                    array1[i] = data.arr[i];
                }
         })
     }
     return{
         fetchData: fetchData,
         string1: string1,
         string2: string2,
         array1: array1
     }
})();

Если я изменю

string1 = data.string1;

на

namespace.Base.string1 = data.string1;

, он будет работать так, как я хочу.

Так что мой вопроспочему массив1 установлен правильно, если он установлен в той же области видимости, что и строки?

Кроме того, каково средство для установки переменных уровня модуля из функций модуля без необходимости указывать глобальный путь (например,namespace.Base.string1)

Ответы [ 3 ]

3 голосов
/ 04 ноября 2010

Проблема в том, что у вас на самом деле есть две разные ссылки: переменная string1 в закрытии анонимной функции, которую вы вызываете для создания namespace.Base, и namespace.Base.string1, которая находится на объекте, возвращенном из этой анонимной функции , Присвоение переменной string1 свойству объекта string1 является одноразовым набором, а не живой ссылкой. Дальнейшее изменение переменной string1 не повлияет на свойство объекта. Вот что вы хотите:

namespace.Base = (function() {
  var my = {
    string1: null,
    string2: null,
    array1: [],
    fetchData: function () {
      $.getJSON('backendScript.php', function(data){
        my.string1 = data.string1;
        my.string2 = data.string2;
        var arrayCount = data.arr.length;
        for (var i = 0; i < arrayCount; i++){
          my.array1[i] = data.arr[i];
        }
      });
    }
  };
  return my;
})();

Теперь локальные, но общедоступные члены namespace.Base находятся в объекте my. Вы можете создавать закрытые переменные, используя var в анонимной функции, или создавать дополнительные открытые свойства, добавляя их в my.

1 голос
/ 04 ноября 2010

Было бы неплохо познакомиться с замыканиями и их работой:

Как работают закрытия JavaScript?

0 голосов
/ 04 ноября 2010

Ваша проблема с областью действия на самом деле не является проблемой области действия.Проблема заключается в том, что массивы являются указателями на свои данные, а строки - нет.

namespace.Base устанавливается на результаты (возвращаемое значение) анонимной функции.- Он задан как объект, содержащий функцию ref (fetchData), две пустые строки и массив.

Если позже вы вызовете функцию fetchData, он изменит содержимое массива1.Но он также создаст две новые строки (из data.string1 и data.string2).Старые значения string1 и string2 (которые являются namespace.Base.string1 и namespace.Base.string2) не изменены.Таким образом, они оставляются как пустые строки (не то, что вы хотите).

Пример этого.Попробуйте это в Firebug -

s1 = "Hi";
s2 = s1;  // s2 => "Hi"
s1 = "Bye" 
alert(s2); // *** s2 is still "Hi", it was not changed!

// But arrays are different:
a1 = ["Hi"];
a2 = a1;
a1[0] = "Bye";
alert(a2[0]); // a2[0] is now "Bye"  

Добавлено: ошибка синхронизации асинхронных данных

Также обратите внимание, что ваш код неверен в том виде, в котором он написан, поскольку вы не сообщаете вызывающему.любой способ узнать, когда завершился Ajax-вызов:

namespace.Base.fetchData(); // starts the Ajax call via getJSON method
var a = namespace.Base.array1; // ERROR!! The value of namespace.Base.array1 is
                               // indeterminate since you don't know if the
                               // the Ajax request has completed yet or not!

Вы, похоже, пытаетесь преобразовать асинхронный Ajax-вызов (который вызывает функцию обратного вызова после получения ответа от удаленного сервера) всинхронный вызов, который не вернется, пока не будут получены результаты.

Это действительно плохая идея.(Если вы хотите узнать больше, задайте еще один вопрос в SO.)

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