Передать статическое значение в динамическую функцию Javascript - PullRequest
0 голосов
/ 14 сентября 2011

Так что я уверен, что это простой вопрос, но я не смог понять это.Ниже показана функция, которая создается и добавляется к маркеру карты Google в событии mousedown.Это создается для каждого повторяемого маркера.

Часть, исключающая меня, находится в строке 5 ниже 'pickupVenue (data [i] .id)' ', значение, переданное в этом вызове функции, всегда является последним итерированным значением.Я хочу вставить статическое значение того, что я повторяю при создании каждого маркера.

for (i in data) {
    google.maps.event.addListener(marker, 'mousedown', function() {
        state = PINCH;
        map.setOptions({draggable: false});
        timeoutId = setTimeout(function() { pickupVenue(data[i].id) }, 1000); 
    });
}

---- рабочий результат ----

google.maps.event.addListener(marker, 'mousedown', pickupMarker(data[i].Listing.id));

function pickupMarker(id) {
    return function() {
        state = PINCH;
        map.setOptions({draggable: false});
        timeoutId = setTimeout('pickupVenue('+id+')', 1000);
    }
}

Ответы [ 3 ]

2 голосов
/ 14 сентября 2011

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

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

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

Например:

function createListener( i ) {
    return function() {
        state = PINCH;
        map.setOptions({draggable: false});
        timeoutId = setTimeout(function() { pickupVenue(data[i].id) }, 1000); 
    };
}

for (i in data) {
    google.maps.event.addListener(marker, 'mousedown', createListener( i ) );
}

Здесь я создал createListener() функцию и передал в нее i.

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

Тогда createListener() возвращает эту функцию слушателя, которая передается в качестве третьего аргумента addListener().

1 голос
/ 14 сентября 2011

Улучшенная версия от ответа закрытия IAbstractDownvoteFactor:

for (i in data) {
    google.maps.event.addListener(marker, 'mousedown', function() {
        state = PINCH;
        map.setOptions({draggable: false});

        var timeoutFn = function(theId) {
            return function realTimeoutFn() {
                pickupVenue(theId); // value of "theId" is kept
            };
        };

        timeoutId = setTimeout(timeoutFn(data[i].id), 1000); 
    });
}
0 голосов
/ 14 сентября 2011

Я вижу, что этот вопрос с setTimeout() возникает так часто, и всегда сложно вспомнить правильный синтаксис замыкания, поэтому я подумал, что, возможно, нам следует просто создать служебную функцию setTimeoutWithData(), которая сделает это действительно простым. Итак, вот оно:

function setTimeoutWithData(rock, fn, t, ctx) {
    ctx = ctx || window;
    function localFn() {
        fn.call(ctx, rock);
    }
    return(setTimeout(localFn, t));
}

Он принимает четыре параметра и возвращает идентификатор таймера:

rock

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

fn

Это ваша функция обратного вызова. В качестве параметра будет передан камень, поэтому ваш обратный вызов должен быть объявлен так: function fn(rock) {}

t

Это значение времени setTimeout в мс, такое же как setTimeout.

ctx

Это единственный необязательный параметр. Если вы хотите, чтобы ваш обратный вызов имел определенное значение this, вы можете настроить его с помощью параметра ctx. Помимо прочего, это позволяет вам использовать setTimeoutWithData для вызова метода объекта и правильно установить this, чтобы он легче работал с объектно-ориентированным программированием. Если ctx не передан, то this будет установлен на window (так же, как setTimeout).

Итак, проблема в исходном вопросе здесь будет решена так:

for (i in data) {
    google.maps.event.addListener(marker, 'mousedown', function() {
        state = PINCH;
        map.setOptions({draggable: false});
        timeoutId = setTimeoutWithData(data[i].id, function(anID) { pickupVenue(anID) }, 1000); 
    });
}

И вот пример приложения, показывающего эту функцию утилиты в действии: http://jsfiddle.net/jfriend00/3SUAJ/.

...