Вопрос
Как функция обратного вызова сохраняет локальную переменную, откуда она была создана?
Простой пример
Я создаю видеоплеер. Он будет иметь ползунки для управления насыщенностью, контрастностью и оттенком. Когда пользователь играет с ползунками, он должен признать, какой слайдер был изменен и какое значение он изменил. Проблема заключается в том, что имя слайдера является локальной переменной из области создателя этого обратного вызова onChange. Как этот обратный вызов может сохранить имя ползунка?
HTML
<div id="saturation">
<div class="track"></div>
<div class="knob"></div>
</div>
</div>
<div id="contrast">
<div class="track"></div>
<div class="knob"></div>
</div>
</div>
<div id="hue">
<div class="track"></div>
<div class="knob"></div>
</div>
</div>
JS
var elements = [
'saturation',
'contrast',
'gamma'
];
for(var i = 0; i < sliders.size(); i++) {
new Control.Slider(
$(elements[i]).down('.knob'),
$(elements[i]).down('.track'), {
onChange: function(value) {
// ERROR: elements[i] is undefined
alert(elements[i] + ' has been changed to ' + value);
}
}
}
Ответ 1
Та же переменная, i
- значение которого заканчивается как 4 - привязано к каждой функции, которую вы создаете внутри цикла. Вы можете обернуть функцию в другую функцию, которую вы вызываете на месте, и передать i
в качестве параметра этой функции:
for(var i = 0; i < sliders.size(); i++) {
new Control.Slider(
$(elements[i]).down('.knob'),
$(elements[i]).down('.track'), {
onChange: (function(inner_i) { function(value) {
alert(elements[inner_i] + ' has been changed to ' + value);
} })(i)
}
}
Ответ 2
Создайте копию переменной для каждого обратного вызова, вы можете сделать это с помощью анонимной функции, которую вы передадите в значение:
for(var i = 0; i < sliders.size(); i++) {
(function(e) { // get a local copy of the current value
new Control.Slider(
$(elements[e]).down('.knob'),
$(elements[e]).down('.track'), {
onChange: function(value) {
// ERROR: elements[e] is undefined
alert(elements[e] + ' has been changed to ' + value);
}
}
})(i); // pass in the current value
}
Таким образом, вы не ссылаетесь на те же самые i
X.
Ответ 3
Поместите свою функцию в закрытие таким образом:
for(var i = 0; i < sliders.size(); i++) {
(function(q){
new Control.Slider(
$(elements[q]).down('.knob'),
$(elements[q]).down('.track'), {
onChange: function(value) {
// ERROR: elements[q] is undefined
alert(elements[q] + ' has been changed to ' + value);
}
}
})(i)
}