Как передать переменную по значению в анонимную функцию JavaScript?

StackOverflow https://stackoverflow.com/questions/1203876

Вопрос

Цель

Я хочу динамически назначать обработчики событий некоторым элементам div на страницах сайта.

Мой метод

Я использую jQuery для привязки анонимных функций в качестве обработчиков для выбранных событий div.

Проблема

Код повторяет массив имен div и связанных с ними URL. Имя div используется для установки цели привязки, то есть присоединения этого обработчика к этому событию div.

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

Таким образом, идея заключается в том, что если пользователь наведет курсор мыши на определенный элемент div, он должен запустить анимацию выдвижения для этого элемента div. Но вместо этого при наведении мыши на div1 (rangeTabAll) запускается анимация выдвижения для div4 (rangeTabThm). То же самое верно для div 2, 3 и т. Д. Порядок не имеет значения. Измените элементы массива вокруг, и события всегда будут нацелены на последний элемент в массиве, div4.

Мой код - (использует jQuery)

var curTab, curDiv;
var inlineRangeNavUrls=[['rangeTabAll','range_all.html'],['rangeTabRem','range_remedial.html'],
                ['rangeTabGym','range_gym.html'],['rangeTabThm','range_thermal.html']];
        for (var i=0;i<inlineRangeNavUrls.length;i++)
        {
            curTab=(inlineRangeNavUrls[i][0]).toString();
            curDiv='#' + curTab;
            if  ($(curDiv).length)
            {
                $(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);} );
                $(curDiv).bind("mouseout", function(){showHideRangeSlidingTabs(curTab, false);} );
            }
        }

Моя теория

Я либо не вижу ослепительно очевидную синтаксическую ошибку, либо проблему передачи по ссылке. Первоначально у меня было следующее утверждение, чтобы установить значение curTab:

curTab=inlineRangeNavUrls[i][0];

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

Так что мне действительно нужно было передать curTab значение обработчикам событий анонимной функции, а не ссылку curTab object .

Итак, я подумал:

curTab=(inlineRangeNavUrls[i][0]).toString();

решит проблему, но это не так. Та же сделка Очевидно, я упускаю некоторые ключевые и, возможно, очень базовые знания о проблеме Спасибо.

Это было полезно?

Решение

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

Однако простое перемещение объявления переменной в цикл не приведет к этому, потому что JavaScript не вводит новую область видимости для произвольных блоков .

Один из простых способов заставить новую область видимости - использовать другую анонимную функцию:

for (var i=0;i<inlineRangeNavUrls.length;i++)
{
  curDiv='#' + inlineRangeNavUrls[i][1];
  if ($(curDiv).length)
  {
    (function(curTab)
    {
      $(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);} );
      $(curDiv).bind("mouseout", function(){showHideRangeSlidingTabs(curTab, false);} );
    })(inlineRangeNavUrls[i][0]); // pass as argument to anonymous function - this will introduce a new scope
  }
}

As Джейсон предлагает , вы действительно можете немного почистить это, используя встроенный в jQuery функция hover () :

for (var i=0;i<inlineRangeNavUrls.length;i++)
{
  (function(curTab) // introduce a new scope
  {
  $('#' + inlineRangeNavUrls[i][1])
    .hover(
      function(){showHideRangeSlidingTabs(curTab, true);},
      function(){showHideRangeSlidingTabs(curTab, false);} 
    );
  // establish per-loop variable by passsing as argument to anonymous function
  })(inlineRangeNavUrls[i][0]); 
}

Другие советы

Что здесь происходит, так это то, что ваши анонимные функции образуют замыкание и уносят с собой свои внешние рамки. Это означает, что когда вы ссылаетесь на curTab внутри вашей анонимной функции, когда обработчик событий запускает эту функцию, он будет искать значение current curTab во внешней области видимости. Это будет то, что вы в последний раз назначали curTab. (не то, что было назначено в то время, когда вы связали функцию)

вам нужно изменить это:

$(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);} );

на это:

$(curDiv).bind("mouseover", 
    (function (mylocalvariable) { 
        return function(){
            showHideRangeSlidingTabs(mylocalvariable, true);
        } 
    })(curTab) 
);

это скопирует значение curTab в область видимости внешней функции, которую внутренняя функция возьмет с собой. Это копирование происходит одновременно с привязкой внутренней функции к обработчику событий, поэтому " mylocalvariable " отражает значение curTab в то время. Затем в следующий раз в цикле будет создана новая внешняя функция с новой областью действия, и в нее будет скопировано следующее значение curTab.

Ответ shog9 в основном делает то же самое, но его код немного более строг.

Это довольно сложно, но имеет смысл, если подумать. Закрытия странные.

edit: упс, забыл вернуть внутреннюю функцию. Фиксированный.

Я думаю, ты делаешь это более сложным, чем нужно. Если все, что вы делаете, это назначаете скользящий эффект при наведении курсора мыши, попробуйте hover эффект с помощью jquery.

$("#mytab").hover(function(){
    $(this).next("div").slideDown("fast");},
  function(){
    $(this).next("div").slideUp("fast");
});

Если вы разместите полный HTML-код, я точно скажу вам, как это сделать:)

Вы можете поместить значение вашей переменной в несуществующий тег, а позже вы можете прочитать их оттуда. Этот фрагмент является частью тела цикла:

 s = introduction.introductions[page * 6 + i][0]; //The variables content
 $('#intro_img_'+i).attr('tag' , s);              //Store them in a tag named tag
 $('#intro_img_'+i).click( function() {introduction.selectTemplate(this, $(this).attr('tag'));}  );  //retrieve the stored data
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top