Programming languages use scoping to manage the visibility of variables throughout a program's execution path.

While many languages are block-scoped (if block, for loop, curly braces), Javascript is function-scoped, meaning new scopes are created through function definitions. Scopes are chained by nesting functions.

Local or immediate scopes have access to surrounding scopes. However surrounding (outer) scopes do not have access to nested scopes. Think of it as a car with heavily tinted windows. The person on the outside is not able to see in but the person on the inside can see out.

There is one global scope which wraps all function scopes. If a variable is defined without preceding it with "var" it's hoisted (more on hoisting later) to the global scope. In the browser, global scope is maintained by "window" object.

In the above example, there are two scopes - global and function. The function scope has access to all variables in its own scope and the surrounding global scope; Those being passenger: function scope, person: global scope and position: global scope.

This is evident in line: 5 which references passenger, person and position without error.

Line 11, in the above example, throws a ReferenceError because of an attempt to access the passenger variable, which is hidden in the nested function scope.

Javascript implements function-scoping using a technique commonly referred to as lexical scoping.

Lexical (static) Scope

Lexical scoping relates the closest surrounding scope to an identifier's exact location in the code. This is often referred to as static scoping because we're able to determine the scope of an identifier by looking at (parsing) the identifier's exact location (static position) in the script text, prior to runtime . Later we will see that this is not entirely correct due to something called "hoisting".

Lexical scoping relates the closest surrounding scope to an identifiers exact location in the code

Line 4 in scopeOne is able to reference it's variables by having first looked in its immediate local scope and then, having not found the required identifiers, progressed to the next scope in its scope chain. In this case, the next scope is the global scope which contains 'name' and 'language' on Line 1.

The next function, scopeTwo, introduces variable name shadowing. Recall reference assignment is always applied to the closest scope. In this case, name on line 12, references variable name declaration on line 11, even though name is visible in line 9 and line 1. Here, name on line 11 is said to shadow name on line 9. Likewise, name on line 9 shadows name on line 1.

A more interesting example is scopeThree function, which executes scopeOne declared outside of scopeThree. Although scopeThree contains variables with identical names to those used in scopeOne, scopeOne does not have access to scopeThree's scope because it is not an outer scope of the scopeOne's function declaration. Instead scopeOne references global variables on line 1 as they are the closest scoped variables. If we removed line 1, scopeOne would raise a ReferenceError.

The take away point is to focus on the closest scope of the function or variable declaration.

Hoisting

Hoisting applies to both function and variable declarations. Given our knowledge of scoping thus far, it's a natural progression to understand the workings of hoisting.

Function declarations and variable declarations are always moved ("hoisted") invisibly to the top of their containing scope for pre-processing by the Javascript interpreter.

Hoisting Variable Declarations

Hoisting Variable Declarations follow two simple rules:

Pull the declaration to the top of the function

Initialise the identifier in place

In the following example, one might be deceived into thinking a ReferenceError should occur as a result of the code on line 2. This would be true if Javascript followed static scoping to the letter; But, Javascript interpreters use hoisting in order to know all declarations within a scope prior to execution.

Example before hoisting:

1: function scopeOne() {
2: writeln('My name is ' + name); // my name is undefined
3: var name = 'james';
4: writeln('and now my name is ' + name); // and now my name is james
5: }

Example after hoisting:

1: function scopeOne() {
2: var name;
3: writeln('My name is ' + name); // my name is undefined
4: name = 'james';
5: writeln('and now my name is ' + name); // and now my name is james
6: }

After hoisting, only the variable declaration has changed location in the script text; all other lines, including the variable initialisation, remain in the same position.

Note: To minimise surprises resulting from hoisting, it's best to declare all locally scoped variables at the top of a function.

Hoisting Functions

Similarly, functions are also hoisted to the top their containing scope.

It's actually function hoisting that allows you to call functions that are defined further down in the script text.

Before proceeding - a short clarification of terms: Function Declaration vs Function Expression

Unlike variable hoisting, which only hoists the variable declaration, function declarations are hoisted, as definition and body. This is a subtle but important point. Lets mix function and variable hoisting to test our understanding.

Instead of using a function declaration, we are now using a function expression, which assigns an anonymous function to a variable. therefore replacing function hoisting rules, used in previous example, with variable hoisting rules.

We know variable hoisting raises the variable declaration to the top of scope, leaving the initialisation (in this case the anonymous function) in its original place.

Hoisting still occurs, but with one set of hoisting rules to contend with, these changes should not be an issue. You can see in the example below that the hoisting step still happens although the effects are of little concern.

In this post, I've covered lexical scoping of function and variable declarations, including the effect hoisting has on scope. These concepts lay the ground-work for understanding many of the advanced concepts in Javascript (ES 5.1) programming.

The model presented is simplistic, avoiding discussion of objects and their properties, functions as objects and execution context state management. However, while simplistic, it is a good basis from which to build our understanding of objects, context, identifier resolution and closures. I'll present a new model to cover these concepts in my next post.

We know:

Javascript employs function scope only.

Nested functions can see their containing functions but containing (outer) functions cant see inside of nested functions

Nesting functions create a scope chain which terminates at the global scope.

Hoisting applies to both functions and variable declarations within scope

Hoisting rules differ for variable and function declarations. These rules catch out the noob and experienced developers alike.

Your blog is really awesome. Thank you for your sharing this informative blog. Recently I did HTML5 Training in Chennai at FITA academy, Its really useful for me. Suppose if anyone interested to learn real time PHP Training in Chennai reach FITA.