2011-01-30 3 views
1

Может кто-нибудь помочь мне с загадкой JavaScript?JavaScript - сохранение переменных внутри функций без вызова функций

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

var a[]; 

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

a[5](); 

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

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

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

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

ответ

6

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

Пример: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 = []; 
+1

элегантный и хорошо объяснил и комментарий ниже! +1 –

4

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

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);}; 
} 
+0

большое спасибо! –

1

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

var a[]; 

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

a[5](); 

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

+1

-1 @levu вам необходимо вернуть функцию. Вы просто определили, что [i] не определено здесь. – Raynos

+0

@raynos: u r right :) – levu

1
var a[]; 

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

a[i = 5](); 

Чит, так как (я = 5) === 5

Не Actaully сделать это

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

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

var a = []; 

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

a[i](); 

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

+0

очень плохое решение ... – levu

+0

@levu, но это забавно думать вне рамки решения! Если это вопрос интервью, я скорее отвечу на это. – Raynos

+0

Я бы сказал, что это не решение его проблемы;) Это решение. Это похоже на генотип против фенотипа. Это решение фенотипа. – levu

0

Причина ваш первый пример не работает это, данные должны быть сохранены где-то. У вас есть десять разных значений для хранения, но только одна переменная 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, который вызывает его без аргументов? В этом случае выполняйте функцию закрытия, которая делает-a-функцию.

+0

Мне жаль, что я не могу голосовать +2;) –

+2

Это не ответит на вопрос. Бывают случаи, когда вам нужно закрыть текущее значение 'i' в цикле с функцией, которая будет помнить это значение, чтобы ссылаться на что-то другое с тем же индексом. Я почти уверен, что это просто простой пример для объяснения концепции. – user113716

+0

Уверен, что есть много возможностей, но если вы знаете индекс, чтобы выяснить, какая из 10 функций для вызова, вы можете так же легко передать эту информацию. Затем вам иногда понадобятся беззаданные функции (обратные вызовы jQuery и т. Д.), , Я не уверен, чего хочет этот плакат. – jpsimons

Смежные вопросы