Как передать значение (а не ссылку) переменной JS в функцию?
Вот упрощенная версия того, что я пытаюсь запустить:
for (var i = 0; i < results.length; i++) {
marker = results[i];
google.maps.event.addListener(marker, 'click', function() {
change_selection(i);
});
}
но я обнаружил, что каждый слушатель использует значение results.length(значение, когда цикл for завершается). Как добавить слушателей таким образом, чтобы каждый из них использовал значение я в момент его добавления, а не ссылку на i?
Ответы
Ответ 1
В современных браузерах вы можете использовать ключевые слова 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);
}
Создавая анонимную функцию и вызывая ее с переменной в качестве первого аргумента, вы передаете значение функции и создаете закрытие.
Ответ 2
Как и замыкания, вы можете использовать function.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))
);
};
};
}
Ответ 3
закрытия:
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
Ответ 4
Вы завершаетесь закрытием. Здесь статья о закрытии и о том, как с ними работать. Проверьте пример 5 на странице; что сценарий, с которым вы имеете дело.
EDIT: Четыре года спустя эта ссылка мертва. Корень проблемы выше состоит в том, что цикл for
замыкает петли (в частности, на marker = results[i]
). По мере того, как marker
передается в addEventListener
, вы видите побочный эффект закрытия: общая "среда" обновляется с каждой итерацией цикла, прежде чем он "наконец-то" будет "сохранен" через закрытие после последней итерации. MDN объясняет это очень хорошо.
Ответ 5
for (var i = 0; i < results.length; i++) {
marker = results[i];
google.maps.event.addListener(marker, 'click', (function(i) {
return function(){
change_selection(i);
}
})(i));
}
Ответ 6
Я думаю, мы можем определить временную переменную для хранения значения i.
for (var i = 0; i < results.length; i++) {
var marker = results[i];
var j = i;
google.maps.event.addListener(marker, 'click', function() {
change_selection(j);
});
}
Я еще не тестировал его.