Область и доступ к внешним переменным в анонимных функциях?

1

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

Я ожидаю, что зарегистрированные значения будут такими: https: server.net/a https: server.net/b

но вместо этого я получаю: https: server.net/b https: server.net/b

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

Зачем? Что я здесь делаю неправильно?

Вот пример кода:

f = [];
items = ['a', 'b'];
for(var i = 0; i < items.length; i++){
    var itemID = items[i];
    var itemAccessUrl = 'https://server.net/${itemID}';

    var func = function(){ 
        console.log(itemAccessUrl);
    };
    f.push(func);
}

console.log(f.length);
for(var j = 0; j < f.length; j++){
    func();
}
Теги:
scope
arrays

2 ответа

1
Лучший ответ

Это связано с природой var varoping. var не является блочным областью, он "поднимается", как если бы вы объявили его в верхней части своей функции.

Вы можете объявить itemAccessUrl, используя let вместо var, который является блочным областью, но зависит от того, какую поддержку браузера вы требуете. (Сказав это, вы используете шаблонные строки, так что вы должны быть в порядке)

  • 0
    Если я изменю itemID и itemAccessUrl на let вместо var, проблема не исчезнет. Если я изменю его на func, то при последующем выполнении получаю ошибку: «функция не определена». Есть ли какой-то другой способ, которым я должен назвать это?
  • 0
    Это из строки вашего второго цикла for. Измените это на f[j](); , В противном случае, вы будете вызывать одну и ту же функцию, всего несколько раз в цикле
Показать ещё 1 комментарий
1

Что здесь происходит? Когда вы вызываете свои функции массива, они используют текущее значение itemAccessUrl, то есть последнюю назначенную строку, с char 'b'. Это происходит потому, что их вызов происходит после завершения первого цикла for.

Вы можете использовать закрытие:

f = [];
items = ['a', 'b'];
for(var i = 0; i < items.length; i++){
    var itemID = items[i];
    var itemAccessUrl = 'https://server.net/${itemID}';

    var func = (function(param) {
        return function () {
            console.log(param);
        };
    })(itemAccessUrl);
    f.push(func);
}

console.log(f.length);
for(var j = 0; j < f.length; j++){
    f[j]();
}

или привязать вашу функцию к текущему параметру:

f = [];
items = ['a', 'b'];
for(var i = 0; i < items.length; i++){
    var itemID = items[i];
    var itemAccessUrl = 'https://server.net/${itemID}';

    var func = (function (param) {
        console.log(param);
    }).bind(null, itemAccessUrl);
    f.push(func);
}

console.log(f.length);
for(var j = 0; j < f.length; j++){
    f[j]();
}

Кроме того, вам нужно изменить второй цикл, вызвав f[j]();

Ещё вопросы

Сообщество Overcoder
Наверх
Меню