Почему я не могу передать значение в JavaScript? - PullRequest
2 голосов
/ 18 ноября 2011
for (id = 50; id < 100; id++)
{
    if($('#'+id).attr('class') == 'myField')  
    {
            $('#'+id).bind('click', function() { install(id); } );
    }
}

Не знаю, почему id не может достичь 'install' в функции (). Я пытаюсь связать каждую кнопку (идентификатор от 50 до 100) с событием щелчка, чтобы вызвать функцию установки (идентификатор). Но, похоже, переменная id не может достичь функции установки. Пока я жестко кодирую это:

for (id = 50; id < 100; id++)
{
      if($('#'+id).attr('class') == 'myField')  
      {
            $('#'+id).bind('click', function() { install( 56 ); });
      }
}

это работает! Пожалуйста, скажите мне, почему.

Ответы [ 5 ]

4 голосов
/ 18 ноября 2011

То, что вы сделали, является одной из самых распространенных ошибок при использовании Javascript-замыканий.

Кстати, сам факт, что эта ошибка настолько распространена, является IMO доказательством того, что это действительно «ошибка» в самом языке.

Javascript поддерживает замыкания на чтение и запись, поэтому при захвате переменной в замыкании записывается не текущее значение переменной, а сама переменная . Это означает, что, например, в

var arr = [];
for (var i=0; i<10; i++)
    arr.push(function(){alert(i);});

каждая из 10 функций в массиве будет содержать замыкание, но все они будут ссылаться на одну и ту же переменную i, используемую в цикле, а не на значение, которое эта переменная имела во время создания замыкания. Поэтому, если вы вызовете любой из них, результат будет одинаковым (например, 10, если вы вызываете их сразу после цикла).

К счастью, обходной путь прост:

var arr = [];
for (var i=0; i<10; i++)
    arr.push((function(i) {
                return (function(){alert(i);});
              })(i));

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

В вашем случае решение таково:

for (id = 50; id < 100; id++)
{
    if($('#'+id).attr('class') == 'myField')  
    {
        $('#'+id).bind('click',
           (function(id){
                 return (function() { install(id); });
            })(id));
    }
}
3 голосов
/ 18 ноября 2011

Когда не достигает install(), я полагаю, вы имеете в виду, что все ваши install(id) ведут себя как install(100).

Причина, по которой это не работает

Это вызвано закрытием javaSctipt. В этой строке function() { install(id) } присваивается id функции обратного вызова install(). Значение id не будет разрешено до тех пор, пока install() не будет вызван, когда намного позже после завершения цикла - время, когда id уже достигнет 100.

Решение - создать другое закрытие, удерживая текущее значение id.

for (id = 50; id < 100; id++)
{
    if($('#'+id).attr('class') == 'myField')
    {
            (function (id) {
              $('#'+id).bind('click', function() { install(id); });
            }) (id);

    }
}

Вот демонстрационный код:

var funcCollections = [];
for (id = 50; id < 100; id++)
{
    if(true)
    {
            (function () {
              var thatId = id;
              funcCollections.push(function () {console.log(thatId,id)});
            }) ();

    }
}

// funcCollections[1]();
// 51 100
// undefined
// funcCollections[2]();
// 52 100
1 голос
/ 18 ноября 2011

Когда вы перебираете переменные и создаете анонимные функции (замыкания), которые ссылаются на переменную цикла, они будут ссылаться на последнее значение

также обратите внимание, что вы не ограничиваете область видимости переменной цикла для цикла for (он не объявлен с помощью var), что означает, что последующие модификации этой переменной будут распространяться на все замыкания.

взгляните на this

1 голос
/ 18 ноября 2011

Это до область действия переменной .

Анонимная функция, которую вы привязываете к событию click элементов $('#' + id), не знает о переменной id в вашемпример кода (при условии, что ваш пример кода является выдержкой из функции).Даже если это произойдет (например, вы объявили id вне какой-либо функции, предоставив ей глобальную область видимости), id будет содержать значение 100 при вызове события click, что не является вашим намерением.

Однако вместо этого можно использовать $(this).attr('id') для получения значения id элемента:

for (id = 50; id < 100; id++)
{
    if($('#' + id).attr('class') == 'myField')  
    {
        $('#' + id).bind('click', function()
        {
            install(parseInt($(this).attr('id')));
        });
    }
}

Ознакомьтесь с документацией jQuery .bind(), он показывает, как this можно использовать из обработчика событий.

1 голос
/ 18 ноября 2011

Нельзя передать переменную в функцию, которую вы привязали. Это теряет ценность. Когда вы передаете '56', это всегда будет 56, но когда вы передаете переменную, JavaScript не будет связывать значение переменной в цикле.

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