передавать переменные в javascript события - без замыканий, без jq, избегать зловредов и тому подобное - PullRequest
2 голосов
/ 20 мая 2011

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

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

for (thisThing in things){
    myDiv=document.createElement('img');

    myDiv.onclick=function(){
        // do somehting!
        // but don't do anything with "thisThing" 
        // because it's got the wrong value in it by the time you call it!
        // but this function has to have the value of "thisThing" to work, dammit!
    }
}
  • Повсюду говорят, что решение этой проблемы - закрытие - вау здорово! кроме перерывов замыкания т.е. (верно?)
  • В противном случае, я могу проверить код на месте, запекать переменные, но в лучшем случае это выглядит некрасиво и кажется, что это может что-то сломать

Так, что это оставляет меня? Все в порядке? оценивается нормально? Я ТОЛЬКО ЧЕЛОВЕК, ДИНАМИЧЕСКИ СОЗДАЮЩИЙ КНОПКИ НА САЙТЕ?!? Любая помощь будет высоко ценится. извините за элементарный и, на самом деле, часто отвечаемый вопрос.

эта страница содержит наиболее полный ответ, который я нашел до сих пор, однако она предполагает, что замыкания являются решением на все времена. Проклятия! http://www.howtocreate.co.uk/referencedvariables.html

Ответы [ 4 ]

9 голосов
/ 20 мая 2011

Закрытия делают , а не ломают IE.

(function(someThing) {
    myDiv.onclick=function(){
       // Access it as "someThing"
    }
})(thisThing);

jsFiddle .

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

К тому времени, когда вы будете готовы щелкнуть элемент, его значение thisThing будет увеличено до конечного значения, которое завершает цикл (последнее свойство, повторяемое в вашем случае), потому что оно обращается к внешней переменной, а не к ее копии.

Создавая новое замыкание с новой самопризываемой функцией и передавая thisThing, его значение становится переменной someThing и живет только внутри внутренней функции.

Это один из способов смягчения этой известной проблемы.

Обратите внимание, что в IE6 & 7 есть утечка памяти. Консультируйтесь с RobG или Ответом Рейноса для решения этой проблемы.

2 голосов
/ 20 мая 2011

Проблема создания функций в циклах: BAD . Немного рефакторинга заставляет вашу проблему исчезнуть.

function createDiv(thing) {
    var div = ...
    div.onclick = ...
}

for (thisThing in things) {
    createDiv(thisThing);
}

Но это все еще приводит к утечке памяти в более старых версиях IE.

Это из-за этого кода:

var div = ...;
div.onclick = function() { ...;

div имеет ссылку на функцию, а функция имеет ссылку на div. Это круговая ссылка. Чтобы устранить эту проблему, вам понадобится фабрика обратного вызова.

function createDiv(thing) {
    var div = ...
    div.onclick = createCallback(thing);
}

function createCallback(thing) {
    return function() {
         ...
    };
}

Это означает, что ваш onclick обратный вызов имеет NO ссылку на ваш элемент div.

1 голос
/ 20 мая 2011

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

> for (thisThing in things){
>     myDiv=document.createElement('img');
> 
>     myDiv.onclick=function(){
>         // do somehting!
>         // but don't do anything with "thisThing" 
>         // because it's got the wrong value in it by the time you call it!
>         // but this function has to have the value of "thisThing" to work,
> dammit!
>     } }

Повсеместно решение для этого называется закрытием

Нет, вы вообще не хотите закрытий. Вы пытаетесь не иметь замыкания.

кроме перерывов закрытия, т. Е. (Верно?)

Неправильно.

Была проблема с IE и циклическими ссылками, включающими элементы DOM, вызывающими утечки памяти. Эта проблема была в значительной степени исправлена, однако ее неправильно поняли. Например:

function addListener(element) {
    var someVar = ...;
    element.onclick = function() {
        // this function has a closure to someVar
    };
}

Вызывает конкретную ссылку, включающую закрытие someVar при вызове addListener. Было несколько довольно простых исправлений для этого. То, что вы хотите сделать, это , а не иметь замыкание для someVar, но использовать значение. Это можно сделать несколькими способами, но самый простой из них:

function addListener (element) { var someVar = ...; element.onclick = (function (differentVar) { оповещения (differentVar); }) (SomeVAr); }

Так что теперь значение для someVar передается в DifferentVar, который является локальной переменной внутренней функции. Конечно, внутренняя функция может все еще иметь замыкание для someVar, но использование использования немедленно вызываемой анонимной функции нарушает замыкание между differentVar и someVar.

Как единое целое, с закрытием все равно нет проблем. Но если вы подключаете несколько слушателей, и все они имеют ссылку на someVar , то все они имеют одинаковое значение. Использование немедленно вызываемой анонимной функции между разрывами этой цепочки.

Редактировать

Извините, последний пример неверен, мой плохой.

function addListener(element) {
    var someVar = ...;
    element.onclick = (function(differentVar) {
        return function() {
          alert(differentVar);
        };
    })(someVAr);
}
0 голосов
/ 20 мая 2011

Закрытия не нарушают IE.

for (thisThing in things){
    if(!things.hasOwnProperty(thisThing)) continue;

    var myDiv = new document.createElement('img');
    myDiv.onclick = (function(thing){
        // Instance specific vars and other thigns
        return function() {
            // More stuff
        }
    })(thisThing);
}
...