Zze Zze - 11 months ago 81
Javascript Question

Anonymous function as callback

I am seeking help understanding why the way I am using anonymous functions are erroring in some circumstances.

In the snippet below I popuplate 2 arrays with functions which are invoked at a later stage.

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

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

var i = 1;
while(i <= 5)

// 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>

Now, I think I understand why
, because at the time of invocation,
i == 6
and becuase it has not been stored as a param within that function at time of creation,
retains it's last known value?

What I really don't understand is why i recieve
TypeError: arr2[c] is not a function
When I change the callback function to:

var func = function(i){

Why does this happen and is this the most appropriate / elegant way to achieve this functionality.

Answer Source

For the first part of the question, you are right, it will retain the latest known value. To avoid that, you need to use closure. For example:

(function(x) {

Closure can often be used as a "scope hack". In this case, it will only ensure that the injected value is the constant current value of i.

For the second part of the question, your confusion is probably caused by the fact that you insert the result of the function (i.e.: func(i)) instead of the function itself (func).

In the first scenario, you return an explicit function(){...} so your array will contain a function that you can call with operator "()".

In the second scenario, in which you return $(<...>).append(), it's not guaranteed anymore that your return value is a function. In that case, the result is "jQuery" (see: jQuery append) and not a function, hence the error is correct. You cannot use the value as a function.

One way out is:




Or probably this:


If needed, it can be helpful to always console.log what is populated inside your arrays before assuming it right. Since Javascript is not a typed language, you may go for a little while before suspecting anything wrong as it will seem work as intended.

Hope this helps!