JavaScript - сохранение переменных внутри функций без вызова функций - PullRequest
1 голос
/ 30 января 2011

Может кто-нибудь помочь мне с загадкой JavaScript?

Рассмотрим следующий код JavaScript:

var a[];

for (i=0;i<10;i++)
{
    a[i] = function(){alert ("I am " + i);};
}

a[5]();

Теперь очевидно, что последняя строка заставит предупреждение читать «Я 9», а не «Я 5», поскольку значение i равно 9 в конце цикла for.

Я хочу, чтобы оповещение выводило «что он должен», но без изменения способа вызова функций из массива, т. Е. Без параметров.

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

Пожалуйста, помогите !!! Спасибо: -)

Ответы [ 5 ]

6 голосов
/ 30 января 2011

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

Пример: http://jsfiddle.net/sX92Q/

var a = [];

for (i = 0; i < 10; i++) {
    a[i] = alertFunc(i);
}

   // return a function that closes around the proper value of "i"
function alertFunc(i){
    return function() {
        alert(i);
    };
};

a[5]();

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

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


Примечание. В javascript это:

var a[];

должно быть:

var a = [];
4 голосов
/ 30 января 2011

Это работает:

var a = [];

for (i=0;i<10;i++)
{
    a[i] = (function(i) {
        return function(){alert ("I am " + i);};
    })(i);
}

a[5]();

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

Чтобы избежать этого, вы должны сделать копию этой переменной, что и делает приведенный выше код.

В качестве альтернативы, в Javascript 1.7 вы бы использовали let определения:

for (i=0;i<10;i++)
{
    let j = i;
    a[i] = function(){alert ("I am " + j);};
}
1 голос
/ 30 января 2011
var a[];

for (i=0;i<10;i++)
{
    a[i] = function(){alert ("I am " + i);};
}

a[i = 5]();

Чит с (я = 5) === 5

Не делайте этого на самом деле

Используйте одно из реальных решений выше.

В качестве альтернативы:

var a = [];

for (i=0;i<10;i++)
{
    (function(j) {
        a[j] = function() { 
            alert ("I am " + j);
        };
    }(i)) 
}

a[i]();

Используйте закрытие, чтобы сделать j текущим значением i

1 голос
/ 30 января 2011

Будет работать следующий код:

var a[];

for (i=0;i<10;i++)
{
    a[i] = (function(i) {
        return function(){alert ("I am " + i);};
   })(i);
}

a[5]();

Здесь i преобразуется в локальную переменную.

0 голосов
/ 30 января 2011

Причина, по которой ваш первый пример не работает, заключается в том, что данные должны храниться где-то .У вас есть десять различных значений для хранения, но только одна переменная i , поэтому она не работает.

Другие авторы предлагают использовать замыкание, которое работает, но ваш вопрос ищетспособ сделать это без вызова функций.Я бы предложил следующее:

var a = [];
for (i=0; i<10; i++) {
  a[i] = function(i){alert("I am " + i);};
}
a[5](5);

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

var whoAmI = function(i){ alert("I am " + i); };
whoAmI(5);

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...