Scope and Closures

Download Examples

First Class Functions

JavaScript's functions are first class, they can be treated as any other variables. That is they can be stored in variables

In this example we create an object my_console which has a copy of two functions inside it, print(), which is just a standard console.log and print_money() which adds a built in formatting function to display the output as US currency.

Like any other function call we need to add a set of parenthesis to execute the function.

 

In this example we have an object other_console which we add a print property to. The value of this print property will be the function my_console.print

We can then call that function using other_console.print() with parenthesis

Another way to do this:

 

Scope in JS

We have 3 categories of scope in JS:

Global (Avoid)

Variables are defined to be global when it is used without an initial definition.

As you can see they can be changed anywhere and everywhere, this becomes much worse when we start working asynchronously and a variable can be changed silently a few seconds after some delayed callback executes.

 

Function Scope (Avoid when possible)

Function scope variables are defined when the var keyword is used. The scope of these variables includes their function body and their parent's function body. Access from outside of these is not allowed.

x is not accessible from outside parent()

Both foo and bar can access variable x, but only foo can access variable y. Once foo returns the reference to y is no longer available.

 

With function scope variables are scoped to functions, but not other blocks (like conditional statements / loop)

 

What happens under the hood is that these declarations are moved to the top where they get declared, they all get the initial value of undefined and variable y never has that changed.

Lexical/Block Scope (suggested)

Variables use lexical scope when declared with the let/const keyword.

Variables are scoped to the block in which they are defined. They can access parent scope variables.

Uncomment these to see each of the errors,

Note programs in JavaScript do not run beyond their first error.

 

Lexical scope describes the behavior of nested functions. In the above example print() is nested inside of foo(). When this occurs, the inner function has a link to all of the variables available in it's parents scope.

 

Any changes made while inside the inner function persist even after the function is no longer in scope.

In the above example bar decreases b in this scenario and this change persists when print() is called.

 

Closures

Lexical Scoping defines how variable names is resolved in nested functions

inner functions contain the scope of parent functions.

A closure adds to this, it is the notion that this continues to apply even after the parent function has returned or is no longer in scope.

 

Higher Order Functions

A higher order function is function that accepts a function as input or returns a function as output. (This one does the latter)

Calling ask() returns a function which we assign to variable whoquestion.

This function ask() checks the type of question, and returns back a function corresponding to that type.

Notice when we make a call to whoquestion() on the next line, we are no longer in the scope of ask(). Yet we can still are able to print out the contents of mytype. This is what closure provides us, access to variables from a parent scope (ask) even if the parent function is no longer in scope.

We cannot access the variable mytype directly however.

 

(Note this demo uses variable mytype to make it explicit that this value would normally would be out of scope, in actual applications it is better to just use type and not create a new variable)

 

A closure is when a function is able to access it's lexical scope even when that function is executed in a different scope.

 

This is not a snapshot

A common mistake is to treat this as a snapshot.

Closure is a preservation of the linkage of the variable, it is not a snapshot of the values.

You close over variables, not values. If you make changes to those variables, those changes persist.

 

In this example our call to use_foo() prints out B, proving that it is not a snapshot but a linkage.

 

Using Closures

Closures are used heavily in asynchronous programming (our next topic) to preserve our ability to access variables after a long delay has occurred, but they are also useful in scenarios where we want to hide implementation details while still revealing an interface.

 

Revealing Module Pattern

This is sometimes called a factory function.

We can create "class" like structures in JavaScript with closures, no need for the this keyword

Notice the return statement, It is returning back an object with all our "public" methods,

The method display_inventory is treated as private and while it can be used internally, our application cannot call it directly outside of the factory function.

This is same with name, age, and inventory.

 

Counters

There will be a bit more that needs to be explained regarding closures, that will be discussed after we introduce asynchronous programming with callbacks.