Here’s a bit of Javascript that prints “Hello World!” on two lines:
(function() {
(function() {
console.log('Hello')
})()
(function() {
console.log('World!')
})()
})()
…except it fails with a runtime error. Can you spot the bug without running the code?
Scroll down for a hint.
Hint
Here’s the text of the error:
TypeError: (intermediate value)(...) is not a function
What’s going on?
Scroll down for the solution.
Solution
One character fixes this code:
(function() {
(function() {
console.log('Hello')
})();
(function() {
console.log('World!')
})()
})()
Without that semicolon, the last function is interpreted as an argument to a function call. Here’s a rewrite that demonstrates what’s going on when the code is run without the semicolon:
const f1 = function() { console.log('Hello'); };
const f2 = function() { console.log('World!'); };
f1()(f2)();
There are 3 function invocations in that last line:
-
f1
is called with no arguments - The return value of
f1()
is called withf2
as its only argument - The return value of
f1()(f2)
is called with no arguments
Since the return value of f1()
is not a function, the runtime throws a TypeError
during the second invocation.
With the semicolon added, this becomes:
const f1 = function() { console.log('Hello'); };
const f2 = function() { console.log('World!'); };
f1();(f2)();
Which runs as expected.
Wait, you had this bug once?
Yup.
Why would you ever write code with so many Immediately Invoked Function Expressions (IIFE)?
It’s a long story - this post explains how I wrote bad enough code to have this bug.
The Lesson
Always use semicolons. This specific case was a bit contrived, but something similar could happen to you. Here’s another Hello World program that fails for a related reason:
const a = 'Hello'
const b = 'World' + '!'
[a, b].forEach(s => console.log(s))
I’ll leave figuring this one out as an exercise for you.
Most Javascript style guides require semicolons, including Google’s, Airbnb’s, and jQuery’s. To summarize: always use semicolons.
Top comments (0)