Передача функции с параметрами в качестве параметра в обратный вызов jQuery

#javascript #jquery

#javascript #jquery

Вопрос:

У меня возникли некоторые трудности с передачей функций. У меня есть этот код:

   var options = [
        { name: "menu 1", func: function (element) { $(element).css("color", "Red"); } },
        { name: "menu 2", func: function (element) { alert("menu 2"); } },
        { name: "menu 3", func: function (element) { alert("menu 3"); } }
    ];

        // This basically creates a div with ul, and li element for each object in options, 
        // and attaches click event to each li that should fire provided func. 
        (function menuMaker(options) {
            var menuDiv = $("<div id='test' />");
            var menuUl = $("<ul>");
            menuDiv.append(menuUl);

            for (var i = 0; i < options.length; i  ) {
                var li = $("<li>"   options[i].name   "</li>");
                // **li.click(function () { options[i].func(menuDiv); });**  
                //>> The line above gives "options[i] is undefined" error. Looks like a scoping issue.

                var userFunc = options[i].func;
                **li.click(function(){ userFunc(menuDiv);});**  
                //>> The line above always fires the last function (alert("menu 3"))

                menuUl.append(li);
            }
            $(document.body).append(menuDiv);
        })(options);
 

и я получаю те ошибки, которые я прокомментировал.
Есть идеи, что я делаю не так?

Спасибо!

Комментарии:

1. В итоге я переписал цикл for следующим образом: for (var i = 0; i < параметры. длина; i ) { var li = $(«<li>» параметры[i].name «</li>»); var func = функция (uf) { функция возврата () { uf(menuDiv); } } // измените область li.нажмите(func(options[i].func)); menuUl.append(li); } Замыкания и область видимости .. Дух!

Ответ №1:

Классический пример неправильного понимания замыканий. Смотрите, как это исправить здесь .

Комментарии:

1. Отличная ссылка! Не могу поверить, что я пропустил это до сих пор.

Ответ №2:

Проблема действительно ограничена. Цикл for не создает новую область, поэтому вам нужно создать ее внутри нее, например:

 for (var i=0; i<10; i  ) {
    (function(i) {
        // "i" will be local here, and be accessible 
        // form any function defined inside this closure
    })(i);
}
 

Ответ №3:

Попробуйте это, которое выполняет итерацию по массиву, добавляя <li> элементы. Вызываемая функция присваивается локальной переменной ‘func’ и затем используется в функции обработчика кликов.

 $.each(options, function() {
    var func = this.func;

    menuUl.append(
        $('<li>').text(this.name).click(function () {
            func(menuDiv);
        })
    );
});
 

Ответ №4:

Удалите аргумент «options» из «(меню функций) (параметры) { «. Переменная options уже установлена вне функции. Добавляя его в качестве аргумента, функция ищет аргумент «options», а не предопределенную переменную options.

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

Проверено! Работает!

 var options = [
    { name: "menu 1", func: function (element) { $(element).css("color", "Red"); } },
    { name: "menu 2", func: function (element) { alert("menu 2"); } },
    { name: "menu 3", func: function (element) { alert("menu 3"); } }
];

(function menuMaker() {
    var menuDiv = $('<div id="test" />'),
        menuUl  = $('<ul />').appendTo(menuDiv);

    for (var i=0; i<options.length; i  ) {

        (function() {
            var func = options[i].func;
            $('<li>'   options[i].name   '</li>')
            .click(function(){ func(menuDiv); })
            .appendTo(menuUl);        
        })();

    }

    $(document.body).append(menuDiv);
})();
 

Комментарии:

1. Я бы предпочел версию, в которой внутреннее замыкание получает аргумент i. Ваше решение работает, потому что он устанавливает промежуточную переменную «func», но сломается, если в обработчике событий будет добавлено любое другое использование «i».