DEV Community

Cover image for Destructuring Tweets - Episode 2 - Hoisting
Kai
Kai

Posted on

Destructuring Tweets - Episode 2 - Hoisting

Hey, welcome to my series about destructuring one of those often shared snippet quizzes on Twitter. Welcome to this week's episode!

Snippet of the Week

This week's snippet is from Jonah Lawrence:

function fooBar() {
  try {
    console.log(foo);
  } catch (error) {
    console.log(error.name);
  }
  try {
    console.log(bar);
  } catch (error) {
    console.log(error);
  }
  var foo = 'hello';
  let bar = 'world';
}

fooBar();
Enter fullscreen mode Exit fullscreen mode

In this snippet, they start with two try/catch blocks. These catch errors and allow us to act upon them, like adding an entry to our log-database or informing the user.
Both of them either print a variable or the name of the thrown object in case of error. Note that both of the trying-to-be-printed-variables are yet to be declared. That missing is the core trickery here.
After the two try/catch blocks, we have the actual declaration of the variables. The first one being initialized via var, the second one with let.

The Output

So, what will the output be if I run the given function? Surprisingly enough, it's undefined and a ReferenceError. To be a little more precise, we print the variable foo (which is undefined at this point), but not the variable bar. Latter is recognized as not declared at all, hence ReferenceError, which semantically means "You did not declare this variable".

Analysis

First things first, why is foo undefined? Shouldn't it be hello? No, because of a concept called hoisting. Javascript engines move the (non-lexical) variable declarations to the top of the scope! What does this mean for our example? This shows how foo gets processed:

function fooBar() {
  var foo; // undefined
  try {
    console.log(foo);
  } catch (error) {
    console.log(error.name);
  }
  foo = 'hello';
}
Enter fullscreen mode Exit fullscreen mode

An uninitialized variable is always just undefined. The variable is declared; hence it can be printed but has not yet an assigned value.
The second and more significant question is why the behavior is not the same for let and var. Easy answer: let is a lexical variable, while var is not. ES6 introduced the difference for precisely this type of errors. The interpreter is more prone to detect hoisting mistakes that way.
A lexical variable behaves like most of us would intuitively expect it to be. One can not access it before it gets initialized. Such are placed in the Temporal Dead Zone (TDZ). Notably, lexical variables, so practically let and const, do not get hoisted.
One addition, one might instantly think that this snippet wants to trick you with scope differences. That's not the case here! The block-scope equals the function-scope.

Snippet Summary

Discussion (2)

Collapse
denvercoder1 profile image
Jonah Lawrence

Awesome explanation!

Collapse
odddev profile image
Kai Author

Thank you!