What is the Execution Context & Stack in JavaScript?

In this post I will take an in-depth look at one of the most fundamental parts of JavaScript, the Execution Context. By the end of this post, you should have a clearer understanding about what the interpreter is trying to do, why some functions / variables can be used before they are declared and how their value is really determined.

What is the Execution Context?

When code is run in JavaScript, the environment in which it is executed is very important, and is evaluated as 1 of the following:

  • Global code – The default envionment where your code is executed for the first time.
  • Function code – Whenever the flow of execution enters a function body.
  • Eval code – Text to be executed inside the internal eval function.

You can read a lot of resources online that refer to scope, and for the purpose of this article to make things easier to understand, let’s think of the term execution context as the envionment / scope the current code is being evaluated in. Now, enough talking, let’s see an example that includes both global and function / local context evaluated code.

Nothing special is going on here, we have 1 global context represented by the purple border and 3 different function contexts represented by the green, blue and orange borders. There can only ever be 1 global context, which can be accessed from any other context in your program.

You can have any number of function contexts, and each function call creates a new context, which creates a private scope where anything declared inside of the function can not be directly accessed from outside the current function scope. In the example above, a function can access a variable declared outside of its current context, but an outside context can not access the variables / functions declared inside. Why does this happen? How exactly is this code evaluated?

Execution Context Stack

The JavaScript interpreter in a browser is implemented as a single thread. What this actually means is that only 1 thing can ever happen at one time in the browser, with other actions or events being queued in what is called the Execution Stack. The diagram below is an abstract view of a single threaded stack:

As we already know, when a browser first loads your script, it enters the global execution context by default. If, in your global code you call a function, the sequence flow of your program enters the function being called, creating a new execution context and pushing that context to the top of the execution stack.

If you call another function inside this current function, the same thing happens. The execution flow of code enters the inner function, which creates a new execution context that is pushed to the top of the existing stack. The browser will always execute the current execution context that sits on top of the stack, and once the function completes executing the current execution context, it will be popped off the top of the stack, returning control to the context below in the current stack. The example below shows a recursive function and the program’s execution stack:

(function foo(i) {
    if (i === 3) {
        return;
    }
    else {
        foo(++i);
    }
}(0));

The code simply calls itself 3 times, incrementing the value of i by 1. Each time the function foo is called, a new execution context is created. Once a context has finished executing, it pops off the stack and control returns to the context below it until the global context is reached again.

There are 5 key points to remember about the execution stack:

  • Single threaded.
  • Synchronous execution.
  • 1 Global context.
  • Infinite function contexts.
  • Each function call creates a new execution context, even a call to itself.

Execution Context in Detail

So we now know that everytime a function is called, a new execution context is created. However, inside the JavaScript interpreter, every call to an execution context has 2 stages:

  1. Creation Stage [when the function is called, but before it executes any code inside]:
    • Create the Scope Chain.
    • Create variables, functions and arguments.
    • Determine the value of "this".
  2. Activation / Code Execution Stage:
    • Assign values, references to functions and interpret / execute code.

It is possible to represent each execution context conceptually as an object with 3 properties:

executionContextObj = {
    scopeChain: { /* variableObject + all parent execution context's variableObject */ },
    variableObject: { /* function arguments / parameters, inner variable and function declarations */ },
    this: {}
}

Activation / Variable Object [AO/VO]

This executionContextObj is created when the function is invoked, but before the actual function has been executed. This is known as stage 1, the Creation Stage. Here, the interpreter creates the executionContextObj by scanning the function for parameters or arguments passed in, local function declarations and local variable declarations. The result of this scan becomes the variableObject in the executionContextObj.

Here is a pseudo-overview of how the interpreter evaluates the code:

  1. Find some code to invoke a function.
  2. Before executing the function code, create the execution context.
  3. Enter the creation stage:
    • Initialize the Scope Chain.
    • Create the variable object:
      • Create the arguments object, check the context for parameters, initialize the name and value and create a reference copy.
      • Scan the context for function declarations:
        • For each function found, create a property in the variable object that is the exact function name, which has a reference pointer to the function in memory.
        • If the function name exists already, the reference pointer value will be overwritten.
      • Scan the context for variable declarations:
        • For each variable declaration found, create a property in the variable object that is the variable name, and initialize the value as undefined.
        • If the variable name already exists in the variable object, do nothing and continue scanning.
    • Determine the value of "this" inside the context.
  4. Activation / Code Execution Stage:
    • Run / interpret the function code in the context and assign variable values as the code is executed line by line.

Let’s look at an example:

function foo(i) {
    var a = 'hello';
    var b = function privateB() {

    };
    function c() {

    }
}

foo(22);

On calling foo(22), the creation stage looks as follows:

fooExecutionContext = {
    scopeChain: { ... },
    variableObject: {
        arguments: {
            0: 22,
            length: 1
        },
        i: 22,
        c: pointer to function c()
        a: undefined,
        b: undefined
    },
    this: { ... }
}

As you can see, the creation stage handles defining the names of the properties, not assigning a value to them, with the exception of formal arguments / parameters. Once the creation stage has finished, the flow of execution enters the function and the activation / code execution stage looks like this after the function has finished execution:

fooExecutionContext = {
    scopeChain: { ... },
    variableObject: {
        arguments: {
            0: 22,
            length: 1
        },
        i: 22,
        c: pointer to function c()
        a: 'hello',
        b: pointer to function privateB()
    },
    this: { ... }
}

A Word On Hoisting

You can find many resources online defining the term hoisting in JavaScript, explaining that variable and function declarations are hoisted to the top of their function scope. However, none explain in detail why this happens, and armed with your new knowledge about how the interpreter creates the activation object, it is easy to see why. Take the following code example:

​(function() {

    console.log(typeof foo); // function pointer
    console.log(typeof bar); // undefined

    var foo = 'hello',
        bar = function() {
            return 'world';
        };

    function foo() {
        return 'hello';
    }

}());​

The questions we can now answer are:

  • Why can we access foo before we have declared it?
    • If we follow the creation stage, we know the variables have already been created before the activation / code execution stage. So as the function flow started executing, foo had already been defined in the activation object.
  • Foo is declared twice, why is foo shown to be function and not undefined or string?
    • Even though foo is declared twice, we know from the creation stage that functions are created on the activation object before variables, and if the property name already exists on the activation object, we simply bypass the decleration.
    • Therefore, a reference to function foo() is first created on the activation object, and when we get interpreter gets to var foo, we already see the property name foo exists so the code does nothing and proceeds.
  • Why is bar undefined?
    • bar is actually a variable that has a function assignment, and we know the variables are created in the creation stage but they are initialized with the value of undefined.

Summary

Hopefully by now you have a good grasp about how the JavaScript interpreter is evaluating your code. Understanding the execution context and stack allows you to know the reasons behind why your code is evaluating to different values that you had not initially expected.

Do you think knowing the inner workings of the interpreter is too much overhead or a necessity to your JavaScript knowledge ? Does knowing the execution context phase help you write better JavaScript ?

Note: Some people have been asking about closures, callbacks, timeout etc which I will cover in the next post, focusing more on the Scope Chain in relation to the execution context.

Further Reading

Chaining Variable Assignments in JavaScript: Words of Caution

Declaring multiple variable expressions on a single line is common practice and also a great shorthand syntax.

However, while reviewing several developer’s work recently, I noticed many are not aware this creates implicit global variables.

(function() {
    var foo = bar = baz = 'local';
    console.log(foo); // local
    console.log(bar); // local
    console.log(baz); // local
}());

Can you spot the problem? Try the following:

var bar = 'funky';
var baz = 'disco';

(function helloworld() {
    var foo = bar = baz = 'local';
    console.log(foo); // local
    console.log(bar); // local
    console.log(baz); // local
}());

console.log(bar);// local, I thought it would be funky
console.log(baz);// local, I thought it would be disco

Multiple variable chaining on the same line creates a leak to the global namespace. Many developers are surprised that local bar and bazinside helloworld() has overwritten global bar and baz.

Why does this happen?

This is because of how operator associativity works in JavaScript, or more simply how operators with the same precedence are evaluated. The interpreter evaluates the = operator as right-to-left associativity.

Therefore the line:

var foo = bar = baz = 'local';

Is easier understood as:

var foo = ( bar = ( baz = 'local' ) );

This is evaluated as baz = 'local', baz has not been declared locally so check the Scope Chain we find baz was declared globally.

The result of this expression is local, which is returned to the next operator bar = 'local'. bar is not declared locally, so look to the Scope Chain or assign it to the global namespace and return the value local.

Finally, var foo = 'local' sees there is no operator preceding foo but the keyword var, so creates a local variable named foo and assigns it the value local.

The Solution

To avoid the global leak, we simply need to separate the variable declarations from assignments:

var bar = 'funky';
var baz = 'disco';

(function helloworld() {

    // method 1
    var foo, bar, baz;
    foo = bar = baz = 'local';

    // or method 2
    var foo = 'local';
    var bar = 'local';
    var baz = 'local';

    // or method 3
    var foo = 'local',
        bar = 'local',
        baz = 'local';

    console.log(foo); // local
    console.log(bar); // local
    console.log(baz); // local

}());

console.log(bar); // funky
console.log(baz); // disco

Now this is better, the local variables are contained in their scope and are completely hidden from the global namespace.

Summary

I actually think this pattern looks quite ugly, having to separate declarations from assignments, but since it stops implicit globals then I’m all for it.

Hopefully after this article I won’t be stumbling across quite as many global namespace leaks in the future!

Dear All Product Managers, You Need Version Control!

Recently, my team over at Richi have had a reoccurring problem in our development process; changing of product requirements. It doesn’t matter which development method you are using, Scrum, Kanban, Waterfall etc, everybody has experienced requirements changing over time, but that’s not the problem.

We have version control, right?

We have had to learn to embrace change, but how are these changes monitored ? For engineering, we use version control systems such as Subversion, Git, Perforce etc and designers have dedicated software such as Adobe Version Cue and PixelNovel Timeline. What about Product Managers ?

Countless times I have seen specs changed by a PM, meaning designs are updated by designers and changes implemented by engineers. Everything seems fine and dandy, except it’s not. Two months pass and more changes from the original spec are made, by this time everyone is rushing to finish development and get the product shipped, slowly forgetting about what or why these changes were made.

This is not just a problem at the startup level, I’ve seen it happen when I was at Yahoo! and Trend Micro, and other colleagues from various companies concur the same.

The same thing happens too often

Here is where my favourite part happens, the QA testing period before production push. On one magical day, the PM decides to start testing the prototype, and notices the product doesn’t have all the features they had asked for, or it’s not functioning according to “The Spec” !

What ? Shock horror ensues and a bug ticket is promptly created and assigned to the engineering team, vaguely saying the feature from “The Spec” is not as expected. Great, the PM thinks, and happily goes back to identifying more problems that diverge from “The Spec”.

Except, it’s not so great. The engineer gets an email alert about the bug ticket, suitably titled “Bug 9999: Missing feature X”. As the engineer’s eyes gaze upon this magnificent bug ticket, he starts to get a gut wrenching feeling and his heart slowly starts to sink. “WTF” passes his lips a few times, “this isn’t a bug ticket, it’s a change request!”.

Here’s the thought process for the engineer:

  • Engineer: Is there even a spec for this ?
  • Engineer: Let me check the spec.
  • Engineer: No there isn’t, I must of missed something, let me check the other specs.
  • Engineer: Still nothing, this really must be a change request, better raise the issue with the PM.
  • PM: Of course it’s in the spec, check spec Z.
  • Engineer: I checked spec Z, there is nothing there.
  • PM: Oh wait, it’s in spec Y.
  • Engineer: No, still can’t find it.
  • PM: I found it ! It was in spec X all along.
  • Engineer: Spec X ? Why is it there ? I’m working on spec Z functionality.
  • PM: Oh, I didn’t think changing that spec would affect this spec.
  • Engineer: My Spec X doesn’t have it, did you just add it to the spec ?
  • PM: No, it was there from the beginning !
  • Engineer: Well, why does mine not have it ?
  • Engineer: Let’s just check the version history.
  • PM: What do you mean version history ? This is it, 1 version, my version with my changes.
  • Engineer:

Ok, so this example is a little exaggerated, but we’ve all been there or had a similar situation. Is Microsoft Word revision control the best PMs can do ? As an industry, we must have better tools we can use to handle changing requests but keep engineering, design and product all happy at once ?

Part of the job for a PM is to manage to product and communications between different dependencies effectively, not forget what changes were made, or how the new changes affect other parts of the product.

Are there any solutions out there that work well equally for a startup as it would for a large corporation ? This post was not set out as a rant about Product Managers, they have a hard enough job as it is, but instead was born out of frustration. I’m hoping there solutions out there, but none that I have come across seem to fit the bill, so for now its back to the drawing board.

Identifier Resolution and Closures in the JavaScript Scope Chain

From my previous post, we now know that every function has an associated execution context that contains a variable object [VO], which is composed of all the variables, functions and parameters defined inside that given local function.

The scope chain property of each execution context is simply a collection of the current context's [VO] + all parent execution context's [VO].

Scope = VO + All Parent VOs
Eg: scopeChain = [ [VO] + [VO1] + [VO2] + [VO n+1] ];

Determining a Scope Chain’s Variable Objects [VO]s

We now know that the first [VO] of the scope chain belongs to the current execution context, and we can find the remaining parent [VO]s by looking at the parent context’s scope chain:

function one() {

    two();

    function two() {

        three();

        function three() {
            alert('I am at function three');
        }

    }

}

one();

The example is straight forward, starting from the global context we call one(), one() calls two(), which in turn calls three(), thus alerting that it is at function three. The image above shows the call stack at function three at the time alert('I am at function three') is fired. We can see that the scope chain at this point in time looks as follows:

three() Scope Chain = [ [three() VO] + [two() VO] + [one() VO] + [Global VO] ];

Lexical Scope

An important feature of JavaScript to note, is that the interpreter uses Lexical Scoping, as opposed to Dynamic Scoping. This is just a complicated way of saying all inner functions, are statically (lexically) bound to the parent context in which the inner function was physically defined in the program code.

In our previous example above, it does not matter in which sequence the inner functions are called. three() will always be statically bound to two(), which in turn will always be bound to one() and so on and so forth. This gives a chaining effect where all inner functions can access the outer functions VO through the statically bound Scope Chain.

This lexical scope is the source of confusion for many developers. We know that every invocation of a function will create a new execution context and associated VO, which holds the values of variables evaluated in the current context.

It is this dynamic, runtime evaluation of the VO paired with the lexical (static) defined scope of each context that leads unexpected results in program behaviour. Take the following classic example:

var myAlerts = [];

for (var i = 0; i < 5; i++) {
    myAlerts.push(
        function inner() {
            alert(i);
        }
    );
}

myAlerts[0](); // 5
myAlerts[1](); // 5
myAlerts[2](); // 5
myAlerts[3](); // 5
myAlerts[4](); // 5

At first glance, those new to JavaScript would assume alert(i); to be the value of i on each increment where the function was physically defined in the source code, alerting 1, 2, 3, 4 and 5 respectively.

This is the most common point of confusion. Function inner was created in the global context, therefore it’s scope chain is statically bound to the global context.

Lines 11 ~ 15 invoke inner(), which looks in inner.ScopeChain to resolve i, which is located in the global context. At the time of each invocation, i, has already been incremented to 5, giving the same result every time inner() is called. The statically bound scope chain, which holds [VOs] from each context containing live variables, often catches developers by surprise.

Resolving the value of variables

The following example alerts the value of variables a, b and c, which gives us a result of 6.

​function one() {

    var a = 1;
    two();

    function two() {

        var b = 2;
        three();

        function three() {

            var c = 3;
            alert(a + b + c); // 6

        }

    }

}

one()​;​

Line 14 is intriguing, at first glance it seems that a and b are not “inside” function three, so how can this code still work? To understand how the interpreter evaluates this code, we need to look at the scope chain of function three at the time line 14 was executed:

When the interpreter executes line 14: alert(a + b + c), it resolves a first by looking into the scope chain and checking the first variable object, three's [VO]. It checks to see if a exists inside three's [VO] but can not find any property with that name, so moves on to check the next [VO].

The interpreter keeps checking each [VO] in sequence for the existence of the variable name, in which case the value will be returned to the original evaluated code, or the program will throw a ReferenceError if none is found. Therefore, given the example above, you can see that a, b and c are all resolvable given function three’s scope chain.

How does this work with closures?

In JavaScript, closures are often regarded as some sort of magical unicorn that only advanced developers can really understand, but truth be told it is just a simple understanding of the scope chain. A closure, as Crockford says, is simply:

An inner function always has access to the vars and parameters of its outer function, even after the outer function has returned…

The code below is an example of a closure:

function foo() {
    var a = 'private variable';
    return function bar() {
        alert(a);
    }
}

var callAlert = foo();

callAlert(); // private variable

The global context has a function named foo() and a variable named callAlert, which holds the returned value of foo(). What often surprises and confuses developers is that the private variable, a, is still available even after foo() has finished executing.

However, if we look at each of the context in detail, we will see the following:

// Global Context when evaluated
global.VO = {
    foo: pointer to foo(),
    callAlert: returned value of global.VO.foo
    scopeChain: [global.VO]
}

// Foo Context when evaluated
foo.VO = {
    bar: pointer to bar(),
    a: 'private variable',
    scopeChain: [foo.VO, global.VO]
}

// Bar Context when evaluated
bar.VO = {
    scopeChain: [bar.VO, foo.VO, global.VO]
}

Now we can see by invoking callAlert(), we get the function foo(), which returns the pointer to bar(). On entering bar(), bar.VO.scopeChain is [bar.VO, foo.VO, global.VO].

By alerting a, the interpreter checks the first VO in the bar.VO.scopeChain for a property named a but can not find a match, so promptly moves on to the next VO, foo.VO.

It checks for the existence of the property and this time finds a match, returning the value back to the bar context, which explains why the alert gives us 'private variable' even though foo() had finished executing sometime ago.

By this point in the article, we have covered the details of the scope chain and it’s lexical environment, along with how closures and variable resolution work. The rest of this article looks at some interesting situations in relation to those covered above.

Wait, how does the prototype chain affect variable resolution?

JavaScript is prototypal by nature and almost everything in the language, except for null and undefined, are objects. When trying to access a property on an object, the interpreter will try to resolve it by looking for the existence of the property in the object. If it can’t find the property, it will continue to look up the prototype chain, which is an inherited chain of objects, until it finds the property, or traversed to the end of the chain.

This leads to an interesting question, does the interpreter resolve an object property using the scope chain or prototype chain first ? It uses both. When trying to resolve a property or identifier, the scope chain will be used first to locate the object. Once the object has been found, the prototype chain of that object will then be traversed looking for the property name. Let’s look at an example:

var bar = {};

function foo() {

    bar.a = 'Set from foo()';

    return function inner() {
        alert(bar.a);
    }

}

foo()(); // 'Set from foo()'

Line 5 creates the property a on the global object bar, and sets its value to 'Set from foo()'. The interpreter looks into the scope chain and as expected finds bar.a in the global context. Now, lets consider the following:

var bar = {};

function foo() {

    Object.prototype.a = 'Set from prototype';

    return function inner() {
        alert(bar.a);
    }

}

foo()(); // 'Set from prototype()'

At runtime, we invoke inner(), which tries to resolve bar.a by looking in it’s scope chain for the existence of bar. It finds bar in the global context, and proceeds to search bar for a property named a. However, a was never set on bar, so the interpreter traverses the object’s prototype chain and finds a was set on Object.prototype.

It is this exact behavior which explains identifier resolution; locate the object in the scope chain, then proceed up the object’s prototype chain until the property is found, or returned undefined.

When to use Closures?

Closures are a powerful concept given to JavaScript and some of the most common situations to use them are:

  • Encapsulation

    Allows us to hide the implementation details of a context from outside scopes, while exposing a controlled public interface. This is commonly referred to as the module pattern or revealing module pattern.

  • Callbacks

    Perhaps one of the most powerful uses for closures are callbacks. JavaScript, in the browser, typically runs in a single threaded event loop, blocking other events from starting until one event has finished. Callbacks allow us to defer the invocation of a function, typically in response to an event completing, in a non-blocking manner. An example of this is when making an AJAX call to the server, using a callback to handle to response, while still maintaining the bindings in which it was created.

  • Closures as arguments

    We can also pass closures as arguments to a function, which is a powerful functional paradigm for creating more graceful solutions for complex code. Take for example a minimum sort function. By passing closures as parameters, we could define the implementation for different types of data sorting, while still reusing a single function body as a schematic.

When not to use Closures ?

Although closures are powerful, they should be used sparingly due to some performance concerns:

  • Large scope lengths

    Multiple nested functions are a typical sign that you might run into some performance issues. Remember, every time you need to evaluate a variable, the Scope Chain must be traversed to find the identifier, so it goes without saying that the further down the chain the variable is defined, the longer to lookup time.

Garbage collection

JavaScript is a garbage collected language, which means developers generally don’t have to worry about memory management, unlike lower level programming languages. However, this automatic garbage collection often leads developers application to suffer from poor performance and memory leaks.

Different JavaScript engines implement garbage collection slightly different, since ECMAScript does not define how the implementation should be handled, but the same philosophy can apply across engines when trying to create high performance, leak free JavaScript code. Generally speaking, the garbage collector will try to free the memory of objects when they can not be referenced by any other live object running in the program, or are unreachable.

Circular references

This leads us to closures, and the possibility of circular references in a program, which is a term used to describe a situation where one object references another object, and that object points back to the first object. Closures are especially susceptible to leaks, remember that an inner function can reference a variable defined further up the scope chain even after the parent has finished executing and returned. Most JavaScript engines handle these situations quite well (damn you IE), but it’s still worth noting and taking into consideration when doing your development.

For older versions of IE, referencing a DOM element would often cause you memory leaks. Why? In IE, the JavaScript (JScript ?) engine and DOM both have their own individual garbage collector. So when referencing a DOM element from JavaScript, the native collector hands off to the DOM and the DOM collector points back to native, resulting in neither collector knowing about the circular reference.

Summary

From working with many developers over the past few years, I often found that the concepts of scope chain and closures were known about, but not truly understood in detail. I hope this article has helped to take you from knowing the basic concept, to an understanding in more detail and depth.

Going forward, you should be armed with all the knowledge you need to determine how the resolution of variables, in any situation, works when writing your JavaScript. Happy coding !

Futures and Promises in JavaScript

With JavaScript usage constantly on the increase, asynchronous event-driven applications are becoming more and more popular. However, a common issue many developers face is with result-dependent operations being used in an asynchronous environment, you often end up with something like:

doA(function(aResult) {
    // do some stuff inside b then fire callback
    doB(aResult, function(bResult) {
        // ok b is done, now do some stuff in c and fire callback
        doC(bResult, function(cResult) {
            // finished, do something here with the result from doC()
        });
    });
});

Since each step requires the previous steps result, you will regularly see a pattern where people start nesting the callback functions within each other’s callbacks. These nested callbacks become difficult to maintain, understand and follow in larger asynchronous applications. Simple async flow such as do (A + B + C) then do D becomes an increasingly complex task.

A solution to use in this situation is the Promise / Futures pattern, which represents the result of a callback that has not happened yet. The concept is quite simple, instead of a function blocking and waiting to complete before returning the result, it simply returns immediately when invoked with an object that promises the future computation / result. This results in a non-blocking behaviour:

doA()
    .then(function() { return doB(); })
    .then(function() { return doC(); })
    .done(function() { /* do finished stuff here */ });

Writing your code using the Promise / Future pattern gives you most of the benefits of using nested callbacks, along with a cleaner, more structured code that is easier to maintain, understand and follow in most asynchronous environments.

Promises / Futures are not the ultimate solution, and there are dozens upon dozens of other solutions that all have their own benefits and drawbacks, each which should be explored in their own right for different situations.