The Executioner: the JavaScript execution context and how to defeat it

JavaScript as the dynamic and versatile language it is provides us with several non intuitive points to be weary of while constructing our code. But before we dig too deep into the issues and their solutions lets review a few facets of the JavaScript’s interpreter.

Execution Context

[Note: also sometimes referred to as Activation Object, Scope Object, Variable Fairy]

Death

Not as scary as it sounds, I assure you. To understand its purpose we need to merely break down its very name. Execution Context, it is the manager of the context of the code that is currently being executed. Quickly, lets take a look at what the execution contexts properties are.

var executionContextObject = {
variableObject:{},
scopeChain:{},
this:{}
};

  • VariableObject – Simply the list of variables/arguments which may be accessed in the function. More on this in a moment.
  • ScopeChain – All the execution context objects containing of all the parent functions.
  • This – the value associated with the current this

Variable Object Array

Lets take a moment to peel back the covers and understand how the variable object works. Now at the point this is happening the interpreter has reached a new function and is creating the execution context for us. These are the steps it will take while creating it.

  1. Look at the inputs||arguments of the function and make an arguments array out of them.
  2. Find each function and and save the pointer to it, if it finds a matching pointer overwrite it with the newest value. Stick results into the Variable Object array.
  3. Find each variable with a var and initialize it to its line assigned value (var me = ‘Ben’) or default which is the “undefined” value. Stick results into Variable Object array.

This array is what lets us do things like this.

var mySweetObject = {
color: "Red",
magicalAbility: "telekinesis"
};

//Normal way to access a property
var color = mySweetObject.color;
//Using the Variable Object Array
var magicalAbility = mySweetObject["magicalAbility"];

The Execution Stack

Now that we understand a bit of how the execution context looks lets take a look at the execution stack. The execution stacks job is to keep track of whats being executed as well as its associated execution context. We can think of it simply as a stack which items are placed on top as they are encountered or LIFO if you prefer that verbiage.

Created By David Shariff

[Image created by David Shariff]

Hoisting

You hear a lot about hoisting, but armed with the above you can tell all of your friends about how simple it is, properly asserting your intellectual superiority over them. Lets look at an example.

console.log(typeof funkyFunction ); // function pointer

var funkyFunction = function(){
return "awesome";
}

Wha, bit odd that myFunkyFunction seems to have a value as though it was declared before its var. But we know that the variable object array is created before the code is executed and therefore is the any inside the scope of this function are created before execution. (Side Note: this does not apply to variables applied to child function)

Scope Chain

Like mentioned before the scope chain is an array which contains all parent execution contexts. Its purpose is to store the location of all variables that the current function can access , this is to facilitate JavaScript’s external variable storage which is represented as lexical scoping.  Lexical scoping simply means functions are stuck with the variables of their parent functions even if called from another physical location.

Use local variables

Now considering the impact of all our variables being stored in physical order, also it is then given they must each be resolved every time a non local variable is utilized. This is a very good reason to be weary of the global scope since it must always be contained in the scope chain. So lighten up on those global declarations, it can save you on bigger JavaScript projects. I have seen scope variables easily reach over 100,000 in big projects, this meaning a serious impact on scan times when the interpreter must resolve variables. But of course use of local variables avoids this entirely, allowing the interpreter to remain in the variable object array.

P.S.

Don’t forget that lack of a var keyword when declaring a variable always lands that variable into the global scope, this includes functions.
Thanks for reading!

Further Reading

Leave a Reply

Your email address will not be published. Required fields are marked *