You Don’t Know JS: My learnings from Scope & Closures

Amy Simmons
5 min readAug 23, 2017

--

TLDR: I’m trying to gain a deeper understanding of JavaScript. I thought I’d do so by reading the You Don’t Know JS (YDKJS) book series. I’m blogging my learnings from the second book, Scope & Closures, here. For more context, check out my earlier post.

I started reading Scope & Closures on a recent flight to Stockholm.

Friday August 11 | 11:00 am

Compilation

The first interesting thing about this book is that it starts off by describing JavaScript as a “compiled” language. It explains that all JavaScript is compiled by the JavaScript “Engine” right before — even milliseconds before — it is executed.

It goes into the compilation process, which is something I know very little about.

The var a = 2; example was helpful. The JavaScript Engine will break down var a = 2;into a separate chunks characters, parse those chunks into what’s called an ‘abstract syntax tree’, then turn that tree into a set of machine instructions to actually create a variable called a (in the compilation phase) and later assign it the value of 2 (in the execution phase).

Scope lookups

I had never heard of LHS (left hand side) and RHS (right hand side) lookups before reading this book. Here’s my understanding of them now:

In the execution phase, the Engine performs two types of variable lookups - LHS and RHS. LHS lookups occur when values are being assigned to variables, as in the var a = 2; example. RHS lookups occur when retrieving the values of variables. Eg when you console.log(a) and, the Engine needs to look up the value of a.

Both types of lookups start searching for the variable at the current scope and work their way up until they either find it, or reach the outer most scope without finding it.

If the variable cannot be found in the scope chain for an LHS lookup, a global variable will automatically be created (when in non-strict mode), or a ReferenceError will be thrown (when in strict mode).

If the variable cannot be found in the scope chain for an RHS lookup, a ReferenceError will be thrown.

So whenever you see a ReferenceError in the console, you can be sure that it relates to a scope failure.

Sunday August 13 | 9:00 pm

Lexical scope

There are two main scope models used in different programming languages — lexical and dynamic.

Lexical scope is what’s used in JavaScript.

Lexical scope is scope that is defined by the JavaScript author at the time of writing the code. (This is a nice way of thinking about scope!). It all comes down to where the author chooses to place his/her variables and functions (and blocks). This placement is what tells the JavaScript Engine where it should perform its LHS and RHS lookups, in other words, the chain of scopes that it needs to move up through to find a variable.

The book gives a really great example of nested scopes as “bubbles inside of each other” here.

eval() and with

eval() and with are bad. I must admit, I didn’t entirely understand the examples here, but the gist is that they’re bad because they “cheat” lexical scope. And the reason cheating lexical scope is bad is because the JavaScript Engine won’t make any of it’s usual performance optimisations, which will result in slower code.

Sunday August 13 | 10:30pm

Hide all the things in functions

The book talks about functions being a way to hide your code, which I hadn’t really thought about before.

[when you put code in a function you create a scope bubble around the code]… which means that any declarations (variable or function) in that code will now be tied to the scope of the new wrapping function, rather than the previously enclosing scope. In other words, you can “hide” variables and functions by enclosing them in the scope of a function.

It also talks about the ‘Principle of least Privilege’, which is that you should expose only what is absolutely necessary and hide everything else.

The downside of the above code snippet is that while the contents of hideThingsInsideMe is hidden from outer’s scope bubble, hideThingsInsideMe itself is not. But alas, IIFE’s to the rescue!

Function declaration vs expression

Three years into my JavaScript journey and I’m finally starting to learn the difference between a function declaration and a function expression. If function is the very first thing in the statement, then it’s a function declaration. Otherwise it’s a function expression.

Just like variable declarations must start with var, function declarations must begin with function.

IIFEs

Did not realise that an IIFE can be written in two different ways! Super cool (though I prefer the first).

Block scope

I knew that let created a block scope, but had completely forgotten that const does the same thing, as does the catch in a try catch statement.

Friday August 18 | 8:30am

Hoisting

I knew about variables being hoisted to the top of their scopes but I didn’t know that functions are also hoisted.

Here’s what I learnt about hoisting from Chapter 4:

All declarations — whether they are variable declarations or function declarations — are processed in the compilation phase, before the assignment and logic happens in the execution phase. Function expressions are not hoisted.

I also didn’t know that functions are hoisted first. I’m still a bit fuzzy on this so let me know if I’ve made a mistake here:

Saturday August 19| 8:00am

Two levels of closure

I really like the way the book distinguishes between simply using a function to close over a set of variables (creating a closure), versus actually calling that function outside of the lexical scope in which it was first created (exercising a closure). The book defines the latter as true closure, closure at its full potential.

I love the definition it gives:

Closure is when a function is able to remember and access its lexical scope even when that function is executing outside its lexical scope.

Tuesday August 22 | 9:30pm

Modules

It’s super interesting to read about modules and the way they exercise closure. I use modules every day at work but until now haven’t actually stopped to think about this.

The module pattern requires the following:

  • An outer function that is invoked at least once, creating a new instance of itself (in the above example this is myModule)
  • The outer function must return back at least one inner function, which has closure over the outer function’s scope, and can later be called to access or modify the private state (in the above example this is sayGreeting)

The end

Book #2 down! So exciting. Can’t wait to read this & Object Prototypes next.

--

--

Amy Simmons

Journalist turned software engineer. Coding for Twitter. Living in San Francisco.