JavaScript Scope and Context – Not the Same Thing!

November 29th, 2011 by Mike Wilcox

In forums and other places I often see people incorrectly use the term scope when they should be using the term context. Scope applies to the variable and functional access of a function, whereas context is the property and method access of a function. Essentially, scope is function-based, and context is object-based.
JavaScript Scope

Scope

The following shows a very simple example of the use of scope. funcA has access to var a, and funcB has access to var b and var a:

Example #1 – Simple Scope

The second log in Example #1 fails because a function captures its scope, and keeps it all to itself. Nobody else has access to funcB‘s scope, not even funcA. However, when funcA captured its scope, it included funcB and therefore funcB has access to all of funcA‘s goodies.

Confused? Try looking at scope as a box made with one-way mirrors. Nothing can see inside the box, but the contents can see out.

Closures

A closure is when you then pass funcB to another function somewhere. The scope of funcB is then captured, or, “enclosed” and passed along with it. An in-depth look at closures is beyond the “scope” (heh heh) of this article, but you can learn more than you ever wanted to know about them from Jibbering.

Context

When learning the JavaScript language, scope gets all of the attention, but the concept that is most difficult to grasp is context. Not knowing what context is and how it works is like trying to learn to paint and not being aware of the color red. The term context can loosely be related to usage of the keyword “this”. Hopefully the following example is obvious:


Example #2 – Simple Context

Both x’s are able to be accessed because this.x is a property within the m() method’s context and var x is a variable within its scope. They do not clobber each other.

That was simple enough, but things start to get tricky when functions are used within methods. Take the following modification to the example:


Example #3 – Broken Context
Refresher: Methods are associated to objects like: object.myMethod = function(){}; while functions are not: var myFunc = function(){}. Properties are associated to objects like: object.myProperty = 96; while variables are not: var myVariable = 96.

Example #3 logs 1, undefined. What happened is that the f() function was treated as a method. In the previous example, this worked because m() was a method and had the context of o. Note the difference between writing o.m = function() and var f = function(): m() has a receiving object while f() has no such object.

One solution to work around the previous nuance is by accessing x through the global object. Instead of this.x, o.x could be used and that would work.

But if the solution is so simple, then what is the need for the keyword this? The reason is you don’t always know what object you’re in, especially with the use of object instances.


Example #4 – Broken Context Instance

Now this.x is part of an instance object, and there can be several, or even hundreds or thousands of object instances. So it becomes impossible or at least unrealistic to try and access the properties via the object name.

So perhaps we should just make f() a method, and then it will have access to this.x?


Example #5 – Context with Broken Scope

Oops. That was definitely not the right thing if you need access to both var x and this.x.

Using Context to fix Scope

So how to fix… this… example? One possible solution is to create f() with this context, within the m() method:


Example #6 – Context Fixing Scope

Now calling this.f(), works pretty well because now not only does f() has the context of the instance1, but it was created within m(), and so it captures that scope, which includes var x.

Using Scope to Fix Context

We’ve probably all run into the following scenario at one time or another.


Example #7 – setTimeout with Broken Context

When I first encountered this situation several years ago, I was perplexed for days. It’s a hard problem to resolve because you don’t really know what’s wrong and what keywords to use to search for solutions.

The problem is the context is broken. The way JavaScript currently works is if a function doesn’t have context, or is not a method associated with an object, it executes in the global space. That should help identify the issue: setTimeout contains an anonymous function that is not associated with this, therefore, this.onTimeout does not resolve correctly.

We can fix this, literally, by assigning it to a variable:


Example #8 – Scope to Fix setTimeout Context

this is nothing more than a keyword that is is used to refer to an object. In this case the object is o, and previously it was the C object instance. Since it is just an object, we can assign it to a variable. By convention, the most popular variable name is self since we are referring to our “self” in a sense. Now when onTimeout is invoked, it is done so with the proper context and the code works correctly.

Conclusion

Knowing the difference between scope and context will not only help you understand the JavaScript language better, but you’ll be better able to communicate with other developers and ask the proper questions. Likewise, knowing the difference between methods and functions, and properties and variables is important to communicate exactly what it is you’re referring to. Remember, var x and this.x are not the same thing!

Tags: , , , , , , ,

2 Responses to “JavaScript Scope and Context – Not the Same Thing!”

  1. [...] Contact Us « JavaScript Scope and Context – Not the Same Thing! [...]

  2. [...] JavaScript Scope and Context – Not the Same Thing! (simply stated: functional scope versus object context [i.e. "this"]) [...]