4

I've stumbled upon one very interesting gotcha, which was really hard to find. Since found, it was not hard to solve, but I'd like to find explanation in order not to repeat something similar in future. Here's a simplified version of my JS-code:

//the following does not work:
var A = function(){
    console.log('I am A')
}
(function B(){
    console.log('I am B');  
})()
A();

I was expecting to see 'I am B', then 'I am A' in console. However, there was Uncaught TypeError: undefined is not a function

After a long debugging I have found out, that the missing semicolon just after A function causes the problem:

//the following works as expected:
var A = function(){
    console.log('I am A')
};
(function B(){
    console.log('I am B');  
})()
A();

Moreover, when you declare the function in other way, everything will be just fine:

//this works too
function A(){
    console.log('I am A')
}
(function B(){
    console.log('I am B');  
})()
A();

So, it's a combination of a variable declaration and parentheses that break the code.

Could you please explain why this happens?

Here's a fiddle for testing: http://jsfiddle.net/wxu2f8en/

Sam Braslavskiy
  • 1,255
  • 9
  • 19
  • 1
    There could hardly be a better example of why not to embrace the ridiculous fashion of omitting semi-colons. –  Oct 05 '14 at 12:43
  • @torazaburo - yes, I agree with you that it's better NOT to omit semi-colons... but in this particular case, you might see a contradiction of two rules: I would doubtlessly write ';' in something like **var a = b;**, but I would not put any semicolons right after the function like **function a(){};** In this case one can overlook function expression and treat it like a function – Sam Braslavskiy Oct 05 '14 at 13:19
  • Function declarations do not end in semi-colons. The closing brace uniquely ends the function declaration, and syntactically nothing else may follow except another statement. If a semi-colon follows a function declaration, it is equivalent to an empty statement. A function on the right hand side of an assignment, on the other hand, even if lexically identical to a function declaration, is a function expression and may legitimately be followed by other stuff such as `()` (even if on a subsequent line). The behavior may be confusing, but it is well-defined. –  Oct 05 '14 at 13:53

2 Answers2

7

This is because without the semicolon, the expression can continue onto the next line. It can help to understand if you remove the linebreak:

var A = function(){
    console.log('I am A')
}(function B(){
    console.log('I am B');  
})()

Here, you create an anonymous function expression, then call it with a single parameter (that's function B). You then call the result of that. However, your first function doesn't return anything, so it returns undefined. Then, you cannot call undefined (undefined is not a function).

However, a function block works differently. That cannot be called on the fly. Therefore, your second example works just fine.

You can read more on MDN:

Scimonster
  • 30,695
  • 8
  • 67
  • 84
1

You need to understand the difference between function expression and function declaration. Function expressions can be invoked immediately, that's why your first anonymous function is called passing function B as parameter. Furthermore, your first function doesn't have a return statement and so, it does return undefined (which is obviously not a function).

JS has an automatic semicolon insertion feature which you shouldn't rely on. Use a tool like JSHint to help you write code that is less error prone.

  • Thanks a lot for your reply! I have upvoted it, since the article you provided (function expression and function declaration) was really helpful and interesting! However, Scimonster has explained the issue earlier, and, though his explanation was a little bit hard to understand, I think It'll be fair if I accept his answer. Once again, thanks a lot for your great help! – Sam Braslavskiy Oct 05 '14 at 12:42