Как я передаю значение (не ссылка) переменной JS к функции? [дубликат]

Этот вопрос уже имеет ответ здесь:

Вот упрощенная версия чего-то, что я пытаюсь выполнить:

for (var i = 0; i < results.length; i++) {
    marker = results[i];
    google.maps.event.addListener(marker, 'click', function() { 
        change_selection(i);
    }); 
}

но я нахожу, что каждый слушатель использует значение results.length (значение, когда для цикла завершается). Как я могу добавить слушателей, таким образом, что каждый использует значение меня в то время, когда я добавляю его, а не ссылка на меня?

116
задан MD Sayem Ahmed 4 January 2013 в 05:23
поделиться

4 ответа

В современных браузерах можно использовать ключевые слова let или const для создания переменной с блочной областью видимости:

for (let i = 0; i < results.length; i++) {
  let marker = results[i];
  google.maps.event.addListener(marker, 'click', () => change_selection(i));
}

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

for (var i = 0; i < results.length; i++) {
  (function (i) {
    marker = results[i];
    google.maps.event.addListener(marker, 'click', function() { 
      change_selection(i);
    }); 
  })(i);
}

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

162
ответ дан 24 November 2019 в 02:16
поделиться

Помимо замыканий, вы можете использовать функцию .bind :

google.maps.event.addListener(marker, 'click', change_selection.bind(null, i));

передает значение i в качестве аргумента функции при вызове. ( null предназначен для привязки this , который вам не нужен в этом случае.)

function.bind был введен платформой Prototype и стандартизирован в Пятое издание ECMAScript. Пока все браузеры не поддерживают его изначально, вы можете добавить свою собственную поддержку function.bind , используя закрытие:

if (!('bind' in Function.prototype)) {
    Function.prototype.bind= function(owner) {
        var that= this;
        var args= Array.prototype.slice.call(arguments, 1);
        return function() {
            return that.apply(owner,
                args.length===0? arguments : arguments.length===0? args :
                args.concat(Array.prototype.slice.call(arguments, 0))
            );
        };
    };
}
35
ответ дан 24 November 2019 в 02:16
поделиться

закрытия:

for (var i = 0, l= results.length; i < l; i++) {
    marker = results[i];
    (function(index){
        google.maps.event.addListener(marker, 'click', function() { 
            change_selection(index);
        }); 
    })(i);
}

EDIT, 2013: Теперь они обычно называются IIFE

13
ответ дан 24 November 2019 в 02:16
поделиться

Вы завершаете закрытие. Вот статья о замыканиях и о том, как с ними работать. Посмотрите Пример 5 на странице; это сценарий, с которым вы имеете дело.

РЕДАКТИРОВАТЬ: Четыре года спустя эта ссылка мертва. Корень проблемы выше в том, что цикл for формирует замыкания (особенно на marker = results [i] ). Поскольку маркер передается в addEventListener , вы видите побочный эффект закрытия: общая «среда» обновляется с каждой итерацией цикла, прежде чем она окончательно «сохраняется» через закрытие после последней итерации. MDN очень хорошо это объясняет.

2
ответ дан 24 November 2019 в 02:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: