Posted in: JavaScript 101

Scope

"Scope" refers to the variables that are available to a piece of code at a given time. A lack of understanding of scope can lead to frustrating debugging experiences. The idea of scope is that it's where certain functions or variables are accessible from in our code, and the context in which they exist and are executed in.

There are two types of scopes in JavaScript: global and local. Let's talk about each of them in turn.

link Global Scope

The first scope is Global Scope. This is very easy to define. If a variable or function is global, it can be accessed from anywhere within a program. In a browser, the global scope is the window object. If a variable declaration occurs outside of a function, then that variable exists on the global object. For example:

1
var x = 9;

Once that variable had been defined, it could be referenced as window.x, but because it exists on the global object we can simply refer to it as x.

link Local Scope

JavaScript also creates a Local Scope inside each function body. For example:

1
2
3
4
5
function myFunc() {
var x = 5;
}
console.log( x ); // ReferenceError: x is not defined

Since x was initialized within .myFunc(), it is only accessible within .myFunc(), and we get a reference error if we try to access it outside of .myFunc().

link A Word of Caution

If you declare a variable and forget to use the var keyword, that variable is automatically made global. So this code would work:

1
2
3
4
5
function myFunc() {
x = 5;
}
console.log( x ); // 5

This is a bad idea. Any variable that is global can have its value changed by any other parts of a program or any other script. This is undesirable, as it could lead to unforseen side effects.

Secondly, Immediately-Invoked Function Expressions provide a way to avoid global variables. You'll see many libraries such as jQuery often use these:

1
2
3
4
(function() {
var jQuery = { /* All my methods go here. */ };
window.jQuery = jQuery;
})();

Wrapping everything in a function which is then immediately invoked means all the variables within that function are bound to the local scope. At the very end you can then expose all your methods by binding the jQuery object to the window, the global object. To read more about Immediately-Invoked Functions, check out Ben Alman's Immediately-Invoked Function Expression article.

Because local scope works through functions, any functions defined within another have access to variables defined in the outer function:

1
2
3
4
5
6
7
8
9
function outer() {
var x = 5;
function inner() {
console.log( x );
}
inner(); // 5
}

But the .outer() function doesn't have access to any variables declared within .inner():

1
2
3
4
5
6
7
8
9
10
11
12
function outer() {
var x = 5;
function inner() {
console.log( x );
var y = 10;
}
inner(); // 5
console.log( y ); // ReferenceError: y is not defined
}

Furthermore, variables that are declared inside a function without the var keyword are not local to the function – JavaScript will traverse the scope chain all the way up to the window scope to find where the variable was previously defined. If the variable wasn't previously defined, it will be defined in the global scope, which can have unexpected consequences.

1
2
3
4
5
6
7
8
9
10
11
// Functions have access to variables defined in the same scope.
var foo = "hello";
var sayHello = function() {
console.log( foo );
};
sayHello(); // "hello"
console.log( foo ); // "hello"

Variables with the same name can exist in different scopes with different values:

1
2
3
4
5
6
7
8
9
10
var foo = "world";
var sayHello = function() {
var foo = "hello";
console.log( foo );
};
sayHello(); // "hello"
console.log( foo ); // "world"

When, within a function, you reference a variable defined in an outer scope, that function can see changes to the variable's value after the function is defined.

1
2
3
4
5
6
7
8
9
10
11
12
var myFunction = function() {
var foo = "hello";
var myFn = function() {
console.log( foo );
};
foo = "world";
return myFn;
};
var f = myFunction();
f(); // "world"

Here's a more complex example of scopes at play:

1
2
3
4
5
6
7
8
9
10
11
12
13
(function() {
var baz = 1;
var bim = function() {
console.log( baz );
};
bar = function() {
console.log( baz );
};
})();

In this instance, running:

1
console.log( baz ); // baz is not defined outside of the function

Gives us a ReferenceError. baz was only defined within the function, and was never exposed to the global scope.

1
bar(); // 1

.bar() may have been defined within the anonymous function, but it was defined without the var keyword, which means it wasn't bound to the local scope and was instead created globally. Furthermore, it has access to the baz variable because .bar() was defined within the same scope as baz. This means it has access to it, even though other code outside of the function does not.

1
bim(); // ReferenceError: bim is not defined

.bim() was only defined within the function, so does not exist on the global object as it was defined locally.