42
var funcs = []
[1, 2].forEach( (i) => funcs.push( () => i  ) )

Why does it produce the error below?

TypeError: Cannot read property 'forEach' of undefined
    at Object.<anonymous>

However, the error goes away if the semicolon ; is added to the end of the first line.

sof
  • 9,113
  • 16
  • 57
  • 83
  • 3
    You should add the semicolon to your lines. The code is been seen as `var funcs = [][1, 2].forEach...` – epascarello Aug 12 '16 at 00:55
  • 3
    You could use `.map()` instead of `.forEach()` at single line `var funcs = [1, 2].map( (i) => () => i )` to avoid issue with semicolon – guest271314 Aug 12 '16 at 01:01

6 Answers6

52

There is no semicolon at the end of the first line. So the two lines run together, and it is interpreted as setting the value of funcs to

[][1, 2].forEach( (i) => funcs.push( () => i  ) )

The expression 1, 2 becomes just 2 (comma operator), so you're trying to access index 2 of an empty array:

[][2] // undefined

And undefined has no forEach method. To fix this, always make sure you put a semicolon at the end of your lines (or if you don't, make sure you know what you're doing).

rvighne
  • 20,755
  • 11
  • 51
  • 73
  • "The expression 1, 2 becomes just 2", can you elaborate a bit? – naveen Aug 12 '16 at 01:01
  • 2
    @naveen When JavaScript sees an expression like `a, b, c`, it evaluates all of the sub-expressions in order, `a`, then `b`, then `c` and then returns the value of the last sub-expression (`c`). This is useful e.g. when the previous expressions are only used for their side effects in a situation where only expressions are allowed, like the first line of a `for` loop. – rvighne Aug 12 '16 at 01:02
  • 3
    Such a classic example of why semicolons should be used, though there are many cases where they are not needed. – jfriend00 Aug 12 '16 at 01:07
  • An even better example calls a method on an array literal after defining a multi-line object literal. In such a scenario, it takes a really sharp eye to spot the lack of a semicolon that would not be needed following the use of braces for block scoping. And even in projects where semicolons are used extensively, how commonly are they used after block scoping? – HonoredMule Jun 13 '17 at 21:27
  • I know what I am doing because I know that before anonymous arrays must be semicolon;;;;) – Timo May 15 '22 at 16:59
4

Keep the semi-colon so the variable declaration of funcs does not include the anonymous array you instantiate as belonging to the variable and also, if you are simply trying to push all the elements of the array into 'funcs' then it should look like:

[1, 2].forEach( (i) => funcs.push(i) )
maxwell
  • 2,313
  • 23
  • 35
  • 1
    I think it's rather clear from the variable name used that the transformation of numbers into functions returning the numbers is quite intentional. Were that not the case, the obvious solution would simply be `var funcs = [1, 2];` – HonoredMule Jun 13 '17 at 21:20
4

we called the forEach method on an undefined value, we got the error.

    const myarr = undefined;

//  Initialize to empty array if falsy
const arr = myarr || [];

//  Using optional chaining
arr?.forEach(element => {
  console.log(element);
});

//  Check if truthy
if (arr) {
  arr.forEach(element => {
    console.log(element);
  });
}

//  Check if Array
if (Array.isArray(arr)) {
  arr.forEach(element => {
    console.log(element);
  });
}
Avnish Jayaswal
  • 161
  • 1
  • 4
1

Whenever we are using an array to loop over bunch of events, it is required to put semicolon to the previous line.

After we query the element we should end the line with semicolon

const el = document.getElementById("giri");
['click', 'touchend'].forEach(event => console.log(event))

I got the above error because I didn't put semicolon before the anonymous array

const el = document.getElementById("giri")
['click', 'touchend'].forEach(event => console.log(event))
Giri Aakula
  • 123
  • 2
  • 9
0

Another solution to this problem is to avoid using anonymous array. No semicolons needed.

var funcs = []
var arr = [1, 2]
arr.forEach( (i) => funcs.push( () => i  ) )
Sylwek
  • 685
  • 1
  • 7
  • 16
0

Add semi-colon in the of first line

var funcs = []; //<-- ; semi-colon added here
[1, 2].forEach( (i) => funcs.push( () => i  ) )
fct
  • 311
  • 3
  • 18