2016-08-28 5 views
1

Я ищу помощь, чтобы понять, почему способ, которым я пользуюсь анонимными функциями, является ошибкой при некоторых обстоятельствах.Анонимная функция как обратный вызов

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

var arr1 = []; 
 
var arr2 = []; 
 

 
// callback function 
 
var func = function(i){ 
 
    return function(){$("body").append(i);} 
 
}; 
 

 
var i = 1; 
 
while(i <= 5) 
 
{ 
 
    arr1.push(function(){$("body").append(i);}); 
 
    arr2.push(func(i)); 
 
    i++; 
 
} 
 

 
// invoke functions 
 
$("body").append("Output from arr1 == "); 
 
for(var c = 0; c < arr1.length; c++){ arr1[c](); } 
 
$("body").append("<br> Output from arr2 == "); 
 
for(var c = 0; c < arr1.length; c++){ arr2[c](); }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Теперь, я думаю, я понимаю, почему arr1 выходы 66666, потому что в момент вызова, i == 6 и becuase ней не были сохранен как пары в этой функции в момент создания, i сохраняет последнее известное значение?

Что я на самом деле не понимаю, почему я получаю TypeError: arr2[c] is not a function Когда я изменить функцию обратного вызова:

var func = function(i){ 
    $("body").append(i); 
}; 

Почему это происходит, и это наиболее подходящий/элегантный способ для достижения этой функциональности ,

+0

потому что он не возвращает функцию в последнем случае. Это ничего не возвращает.e 'undefined' –

+0

проверьте, что вы на самом деле нажимаете на массив:' var fn = func (i); console.log (fn, typeof fn); arr2.push (fn); возможно, это поможет вам понять вашу проблему. – Thomas

ответ

0

Для первой части вопроса вы правы, он сохранит последнее известное значение. Чтобы этого избежать, вам необходимо использовать closure. Например:

(function(x) { 
    arr2.push(func(x)); 
})(i); 

Закрытие часто можно использовать в качестве «взлома области». В этом случае он будет только обеспечивать, чтобы введенное значение было значением постоянного тока i.

Для второй части вопроса ваше замешательство, вероятно, связано с тем, что вы вставляете результат функции (то есть: func(i)) вместо самой функции (func).

В первом сценарии вы возвращаете явный function(){...}, поэтому ваш массив будет содержать функцию, которую вы можете вызвать с помощью оператора «()».

Во втором сценарии, в котором вы возвращаете $(<...>).append(), больше не гарантируется, что ваше возвращаемое значение является функцией. В этом случае результатом является «jQuery» (см.: jQuery append), а не функция, поэтому ошибка правильная. Вы не можете использовать значение как функцию.

Один выход есть:

arr2.push(func); 

Тогда:

arr2[c](c); 

Или, возможно, это:

(function(x){ 
    arr2[x](x); 
})(c); 

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

Надеюсь, это поможет!

+0

Очень полезно - спасибо! Поэтому, когда я '.push (func (i)), это фактически подталкивает возвращаемое значение' func' в массив, а не 'func' сам? – Zze

+1

Точно. 'func (i)' на самом деле является возвращаемым значением 'func' с аргументом' i'. Это может быть неопределенным (ничего), числом, строкой, функцией и т. Д. В большинстве случаев это то, что вы делаете с аргументом, который будет указывать тип возврата. Javascript отрегулирует тип в зависимости от того, каким он должен быть. В C или C++ такой путаницы в отношении типов нет, поскольку он строго типизирован. Однако существует довольно удобный способ избежать этого в JS с помощью 'console.log', который быстро скажет, является ли это Object, Function или постоянным значением. В противном случае 'typeof' сделает это. –

+1

Downvoter, пожалуйста, сообщите о том, как улучшить! Спасибо :) –

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