Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

So I began to mess around with JavaScript today, and I came across a funny case where it seems convinced that something is a function while also convinced that it's not a function. This code illustrates the issue:

var arr1 = Array(1)
for (i = 0; i < arr1.length; i++) {
    arr1[i] = function(n) { return n + i }
}

var arr2 = Array(1)
for (j = 0; j < arr2.length; j++) {
    arr2[j] = function(n) { return arr1[j](n) }
}

typeof arr2[0] // "function"
arr2[0](2)     // TypeError: Property '1' of object [object Array] is not a function

From here, you can assign a variable to arr2[0], and the error persists. I'm not sure if the closures or arrays are necessary to replicate this.

Is there something off with my code, or is this just one of those JavaScript oddities? This isn't something I particularly need an answer to, but it's a little silly so I'd like to know if there's a reason for it.

share|improve this question
1  
Why Array(1) and a loop instead of var arr1 = [function(n) { return n + 1;}];? – Matt Ball Mar 26 at 4:14
This originally occurred while I was experimenting with arrays of closures over loop indices, so I just kept it like that – Stacky McBears Mar 26 at 4:19
Also, @bfavaretto: that's something like what I was originally testing out, and it turns out it has more to do with this than I'd thought (in that the underlying principle of each is the same). So I'm willing to concede this to be a duplicate. – Stacky McBears Mar 26 at 4:42

4 Answers

up vote 2 down vote accepted

This actually does have a bit to do with closures.

First, take this code:

for (j = 0; j < arr2.length; j++) {
    arr2[j] = function(n) { return arr1[j](n) }
}

The variable j initially holds the value 0, thus arr2[0] is set to a reference to a function.

Next, j is incremented, and now has a value of 1. This terminates the loop.

Now, when the function is called:

return arr1[j](n)

Due to closures, j still has its final value of 1. Which is an invalid index in that array.

One more thing to point out. A for loop doesn't create a new closure, so if you're expecting the anonymous function to enclose the value of j within that iteration, that assumption is wrong. There will be a single instance of j within the entire function that j was declared in.

share|improve this answer
Ah, that makes sense (and I've learned that an out-of-bounds index returns undefined rather than throwing an error). Thanks for the speedy answer. – Stacky McBears Mar 26 at 4:38
Yea, arrays just become property bags like any other object. There's nothing stopping you from setting arr2[50] or arr2['bananas'] if you want. – Mike Christensen Mar 26 at 4:44

It's not doing anything weird.

You're just trying to something that isn't a function (the value of arr1[1], which is undefined).

share|improve this answer

It's probably safer to initialize arrays in the form:

var arr1 = [];

Or if you're using 'Array' you should initialize it like this:

var arr1 = new Array();
share|improve this answer

I think you are trying to make use of closure inside the loop, but it doesn't work like that.

If you want to work with the value of i and j in each step of the loop, you have make make use of an anonymous function as shown below.

var arr1 = Array(1)
for (i = 0; i < arr1.length; i++) {
    arr1[i] = (function(i){
        return function(n) { 
            return n + i 
        };
    })(i);
}

var arr2 = Array(1)
for (j = 0; j < arr2.length; j++) {
    arr2[j] = (function(j){
        return function(n) { 
            return arr1[j](n)
        }
    })(j);
}

typeof arr2[0] 
arr2[0](2)

Demo: Fiddle

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.