Chapter 3: Scope and Closure

Scope

Scope is all about whether you can access variables or not. In Javascript, scope is determined by functions! Any variable you declare inside a functions, stay in that function. You're not able to access them. On the other hand, inside the function you can still access any variable that was declared outside it.

If you use C or Java, you might be used to block scope. This does not exist in the current version Javascript (ES5). Writing block scopes is valid syntax, but it's not recommended, because it won't behave like you expect to.

Global scope

Any variable declared in the top scope is the global scope, it will be available anywhere.

One way to check if a variable is the global scope, is by the window object (note: this is a browser quirk). Any global variable will become a property of window. This sounds a bit strange, but the window object is equivalent to the global scope.

It's important to understand how the code flows here. JavaScript won't look inside those function until you invoke them, so the example did not access any variable that wasn't declared. The example shows how that doesn't work:

// it does not work like this:varcat= {
age: year
};
varyear=5;
console.log(year); // 5console.log(cat.age); // undefined

If you want to understand this better, this video might help: https://www.youtube.com/watch?v=QyUFheng6J0

Closures

Closures are perhaps the most powerful yet confusing feature in Javascript. It may be difficult to understand at first, but once you understand this concept, you will have tackled the biggest part of Javascript.

The innerFunction is declared inside the outerFunction, but is not invoked. The innerFunction has access to innerVar, it's in the same scope after all. What happens if we invoke the outer function?

varinF=outerFunction();

The outerFunction is executed and returns the innerFunction. We now have a reference to that inner function.

In other programming languages, everything inside the outerFunction would out of memory after the execution of the function ends. It's all gone! In Javascript it is not, as a matter of fact if we now invoke the innerFunction several times:

Which clearly indicates the innerVar is still alive and well. The outerFunction has created a closure. Every function will do this. Once a function is invoked, all variables inside it will remain in memory.

Hoisting

With function scopes and closures, hoisting is more of a logical consequence. Hoisting is something the browser does when it compiles the Javascript for interpretation. All variables are placed on the top of the current scope (function). For example

It is normally good practice to declare variables as close as possible to the point where you use the variable. Unfortunately, that is not the case with Javascript. With the hoisting it is better to always declare variables on the top!

Gotchas

Closures are incredibly powerful, but also easy to make mistakes with. Two traps when working with closures: (for) loops and asynchronous callbacks. Take a look at this example of preloading images:

One very important thing to reiterate here. There is no such thing as block scope, only function scope! Writing var inside the for loop has absolutely no effect. What really is happening is that we are redefining image 10 times. In the previous example we were also redefining the same function 10 times in onload. We might as well define the onload function on top once and assign it to each image.

Let's take a look at what is actually happening. We are indeed loading 10 different images, however onload is called much later, when the images are loaded. It could be a few milliseconds, or longer, but it could definitely not be so fast that it finished loading during the for-loop. So the for loop ends, i is not assigned as 10 and the browser tries to load images. By the time the images are loaded, onload is called, but the closure still exists! i remains 10 and so it logs "Loaded image number 10" for every image.

If we were to fix this, we simply need to make sure the correct value of i is used the moment onload is called. We could do this by passing i as a parameter.