Variable Hoisting in JavaScript

The JavaScript Variable Scope article covered the basics of variable scope in JavaScript. Today I’d like to continue that discussion, exploring a more complicated concept called hoisting, where the names of variables declared inside of a function are hoisted to the front of the function, so that they may be accessed, even before they are defined.

How do it…

Here is a simple example of hoisting:

function foo() {
    alert(a);
    var a = 1;
}
foo();

You probably expect that the code above would cause an error, because the variable a is used before it is defined. It will actually alert undefined, because the JavaScript interpreter hoists all variable names used inside a function to the front of the function making them available right away (even though they have no value yet). This means that the code above was interpreted like:

function foo() {
    var a;
    alert(a);
    a = 1;
}
foo();

Now that you know what hoisting is, here is a trickier example1:

var foo = 1;
function bar() {
	if (!foo) {
		var foo = 10;
	}
	alert(foo);
}
bar();

This will alert 10, because the if statement does not create an execution context (as in other languages), and bar is interpreted as:

var foo = 1;
function bar() {
    var foo;
	if (!foo) {
		foo = 10;
	}
	alert(foo);
}
bar();

The same would happen, even if var foo = 10; was coded in a way that it would never execute:

var foo = 1;
function bar() {
	if (false) {
		var foo = 10;
	}
	alert(foo);
}
bar();

Here is another tricky example, using function names1:

var foo = 1;
function bar() {
	foo = 10;
	return;
	function foo() {}
}
bar();
alert(foo);

It will alert 1, because bar is interpreted as:

var foo = 1;
function bar() {
    var foo = function() {};
	foo = 10;
	return;
}
bar();
alert(foo);

Keep in mind that hoisting does not occur during scope chain lookups from inner functions:

function foo() {
    console.log(x); // will throw an error
    function bar() {
        x = 1;
    }
    bar();
}
foo();
console.log(x);

The first console.log will throw an error, because x is not hoisted to the execution context of foo. It will be added to window after foo() is called, but not until function bar executes. It will never be added to the execution context of foo().

How it works…

JavaScript has function-level scope, which we call the execution context. Variables declared inside of an execution context are hoisted to the front of the execution context, even if the variables are declared in code that will never execute. The interpreter hoists all variable names, including function names. Variables declared with var will be undefined, while the entire function definition is hoisted. Consequently, I strongly recommend that all variables (including those used by for loops) and functions, should be declared at the front of a function, using a single var statement, to avoid any unintentional hoisting.

function foo(a, b, c) {
    var i = 1,
    	j = 4,
    	baz = "something";

    for (; i < j; i++) {
        alert(baz);
    }
}

Lastly, we should discuss the priority by which variable names enter a scope. There are four basic ways for a variable name to enter an execution context1:

  1. Language-defined: All scopes are, by default, given the names this and arguments.
  2. Formal parameters: Functions can have named formal parameters, which are scoped to the body of that function.
  3. Function declarations: In the form of function foo() {}.
  4. Variable declarations: In the form of var foo;.

For the most part the latest variable name will replace the earlier, so if you define a formal function parameter as foo and then define a function with the same name, then the function would silently replace the formal parameter. The exception to this is variable declarations, which will replace language-defined names, but won’t replace arguments or function declarations.

Hoisting allows you to accidentally do some nasty things, especially if you muck around using reserved words (aka. arguments) for variable names. For this reason, I recommend not reusing variable names, but instead always declaring a new variable when you need to store a new value, and never using reserved words.

References


  1. http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html

JavaScript Variable Scope

JavaScript scopes variables in a unique way that often confuses developers coming from other languages. First, as discussed in the Context Binding Functions article, the this keyword is dynamic, and second, as we᾿ll discuss today, variable scopes change depending on how you declare them.

How do it…

The most basic way to declare a variable is:
 var foo1 = 'bar'; 
The variable foo1 will be added to the current execution ...

OS Boostrap Script for Python/Node Application

Today the EC2 machine that I have been using to run my blog application for the past couple years expires, so I had to move to a new instance. Unfortunately, while I had done a great job of automating the setup for my blog, I had not done a good job of automating the bootstrapping of the operating systems that I use. I think it is really important that system initialization steps be automated, so ...

Context Binding Functions

I realized this week that I have never dedicated an article to context (scope) binding functions in JavaScript and thought I would remedy that today. JavaScript context binding functions are functions that guarantee the execution context of a callback function, allowing the developer to control what this is set to.

How do it…

We’ll look at two types of binding functions. The first, seamlessly wraps an inner callback function with a provided context, so ...

Multi Tab/Window Messaging in JavaScript

I recently implemented a JavaScript only communication system for sending messages between windows/tabs (just referred to as window for the remainder of this document) for Ariba.com. We have a very heavy-handed approach that requires identifying each window and queueing messages in the order that are sent, no matter the originating window. And the final kicker is that it needs to work on some older browsers. We settled on a shared communication channel using ...

Crowd-Sourced Computing on the Web - Proof of Concept

Years ago services like Seti@Home introduced us to crowd-sourcing computing cycles in order to analyze big data. Unfortunately, these programs require that you install some software on your computer and keep it running. Lately, I’ve been noodling over applying this same concept to the web, and I thought I’d share my thoughts. When somebody is viewing a webpage, most of the time the browser is relatively idle, and probably their machine as well. ...

Web Development News - Google's Blink Rendering Engine

Big news in Web Development - Blink Rendering Engine

Google announces that is has forked WebKit and will now be using its own rendering engine, Blink, inside of Chromium. This means in the future web developers will have another platform to test JavaScript and CSS against. The change will affect all Chromium-based browsers, including Opera 14+.

If you want to find out more, PPK has written a really detailed article describing the situation.

Hash-Hack for Cross-Domain IFrame Communication

I recently needed a simple, legacy browser (*cough* IE 6) compatible, solution for sending cross-domain communication between an iframe and its parent window. Fortunately, the URL protocol allows changing the hash part of the URL without causing the page to refresh, and the same is true when updating the URL of an iframe. This means that you can use a hash-hack to communicate between the frames. If you do not need to support < IE ...

Simple JavaScript Requirement System for Asynchronous Scripts

I recently went through the chore of making sure that all the scripts on this site are loaded asynchronously using JavaScript Deferment, as shown in Django Template Tags for JavaScript Deferment. This ended up causing problems with my JavaScript, because most of my scripts depend on blog.js, which is now loaded asynchronously. I decided to write a simple require system that other scripts could use to ensure that blog.js is already loaded, and today ...

Python-Style Decorators in JavaScript

Python-style decorators (or Java annotations) are a useful feature that is not natively available in JavaScript. This article describes a technique for apply Python-style decorators to JavaScript functions. We’ll call them annotations, so not to confuse them with the decorator pattern.

How do it…

To illustrate what an annotation will be, lets try a simple example:
 function alertFoo() { alert('foo'); } alertFoo = annotate(alertFoo).by(alertBar); 
We annotate the alertFoo function ...