1

It might interest somebody and save few hours, a nasty bundling problem, eval is from one file and function is from second file.

eval('console.log(0)')
(function(x){console.log(x)})(1)

will result with: Uncaught TypeError: eval(...) is not a function

and this is the fix

eval('console.log(0)');
(function(x){console.log(x)})(1)

missing semicolon, I've read few times that semicolon in JS optional most of the time.

any comments why eval is not a function in this context?

maciejW
  • 92
  • 1
  • 1
  • 7
  • Though semi colon insertion is optional. It is good to understand that when would JS engine actually insert a semi colon. Reading throug this answer might be helpful https://stackoverflow.com/questions/2846283/what-are-the-rules-for-javascripts-automatic-semicolon-insertion-asi – Abhinav Galodha May 22 '17 at 16:15
  • the lesson from here is always put semicolon between files in bundle :) – maciejW May 22 '17 at 17:01
  • This can happen when you pass some `undefined` variable into `eval`. In my case I didn't imported some global variable in Postman: `eval(globals.some_function)();` – Dedkov Vadim Jan 11 '21 at 20:20

2 Answers2

8

The JS runtime is not perfect at guessing where semi-colons should go.

When it sees this:

eval('console.log(0)')
(function(x){console.log(x)})(1)

It incorrectly assumes that the result of the immediately invoked function expression is part of the eval line (a potential parameter to be passed to the potential function that the eval evaluates to).

Here's an example of when that would work:

eval("(function(message){ alert(message); })")
("Hi there!");

But, in your case, eval is not evaluating to a function, so trying to pass an argument to it fails, thus your error message.

But, it actually has less to do with eval(), in particular. This can pop up anytime a semi-colon is omitted just prior to an IIFE or any expression starting with a (.

Adding the semi-colon, allows the runtime to know that the IIFE is separate.

The rule is that you must insert semi colons on any line that is followed by a ( (as this is how an expression can begin) in order to keep them separate . But, the better rule is to not rely on automatic semi-colon insertion at all and always put them in yourself.

Scott Marcus
  • 57,085
  • 6
  • 34
  • 54
  • this was my guess but finding this was quite a nightmare, because this kind of code was not written by hand, it was concat of many third party libs – maciejW May 22 '17 at 17:00
  • 1
    @maciejW Oh, and by the way, the use of `eval()` is highly discouraged in the first place. It can lead to cross-site scripting attacks, is slow and runs in a modified scope-chain. There is almost always a way to refactor the code to not need `eval()`. – Scott Marcus May 22 '17 at 18:05
1

This is one of the few situations in which Javascript's semicolon insertion will trip you up.

This code:

eval('console.log(0)')
(function(x){console.log(x)})(1)

Is equivalent to this code:

eval('console.log(0)')(function(x){console.log(x)})(1)

In other words, Javascript thinks that the expression eval('console.log(0)') evaluations to a function which you are trying to call with the parameter (function(x){console.log(x)}). That is obviously not what you intended, so you need semicolons at the end of your lines.

Lincoln Bergeson
  • 2,841
  • 4
  • 29
  • 51