Two weeks ago I gave a lightning talk at Caphyon on hoisting in JavaScript. Putting aside all the common jokes about the JS language, people really seemed to like it. It was kind of a challenge to talk about JS while having an audience of C++ and Java colleagues.
Now getting back to the talk, that was lightning ⚡️ fast and it didn’t covered that much as I would’ve liked to. So I’ll try to write a bit more on JavaScript scoping and hoisting bellow.
Hosting Hoisting
On the clickbait talk title, that’s actually a true story. Last time I mentioned the hoisting term into an article of mine, I remember that a friend read it and told me I had a typo in the article.
So what’s hoisting in JavaScript? The short answer is that, conceptually, variable and function declarations are moved/hoisted to the top of their scope before code execution.
Variable declaration
When declaring a variable, only its name gets hoisted.
console.log(name);
var name = "whatever";
// The console logs undefined
Here’s how the above is interpreted, thus undefined
.
var name;
console.log(name);
name = "whatever";
Function declaration
Unlike var, a function declaration hoists its actual definition too.
hello("world");
function hello(p) {
return "Hello " + p;
}
// The console logs "Hello world"
Here’s how the above is interpreted, thus “Hello world”
:
function hello(p) {
return “Hello ” + p;
}
hello("world");
Function expressions
The variable name gets hoisted, but not the function assignment.
hello("world");
var hello = function(p) {
return “Hello ” + p;
}
// TypeError: hello is not a function
Here’s how the above is interpreted, thus hello is not a function
:
var hello;
hello("world");
hello = function(p) {
return "Hello" + p;
}
On ES6 and later
The hoisting behavior isn’t something that applies to latest ECMAScript gems:
- let
- const
- class declaration
- arrow function
// let
console.log(name);
let name = "whatever";
// Uncaught ReferenceError: name is not defined
// const
console.log(name);
const name = "whatever";
// Uncaught ReferenceError: name is not defined
// class declaration
const p = new Rectangle();
class Rectangle {...}
// Uncaught ReferenceError: Rectangle is not defined
// arrow function
console.log(doubled);
const doubled = [1, 2, 3].map(n => n * 2);
// Uncaught ReferenceError: doubled is not defined
Last but not least
Here’s what Brendan Eich said about JS hoisting:
var
hoisting was an implementation artifact. source
function
hoisting was better motivated: function declaration hoisting is for mutual recursion & generally to avoid painful bottom-up ML-like order source
The slides
Here are the slides, just in case.