In reality, code is a highly organized and hierarchical system where processes are synchronized but separated.
Simple principles govern how code is structured and interpreted by computers.
These principles build off of each other, repeatedly compounding to create more complex and efficient applications.
This post will describe two of these principles in particular: scope and context.
Scope and context can seem very similar, and if you get them confused from time to time, don’t feel alone.
One possible reason for this confusion is because scope and context both refer to when variables or certain keywords become relevant, and what exactly they refer to when they’re called upon.
Let’s take a closer look at scope first.
ScopeIn the most simplified of terms, scope has two levels: global scope and local scope.
Global scope refers to variables that are accessible anywhere because they are declared outside of any individual functions or methods — usually at the top of the file.
They exist in the global space, ready to be called upon at any time.
The first example below concerns local scope.
Example of a globally scoped variableLocal scope refers to variables that are accessible within the boundaries of their function.
In this example, we have our initial declaration of the variable dog at the top of our file, which is assigned to the string of “goodBoy.
” Immediately below, we console.
log the dog variable.
As expected, this first console.
log prints ‘goodBoy,’ as seen on the right side of the image.
Then, we have a function of showScopeExample(), which reassigns our dog variable to the string of “badDog.
”This function is immediately invoked, but when we console.
log “dog” for the second time on line 10, it still prints as “goodBoy.
” Even though the second console.
log occurs after we reassign the variable inside of the function, the dog variable is not currently capable of returning as “badDog.
” This is by design.
Our re-declaration of dog inside of showScopeExample() is locally scoped.
The easiest way to know this is to look at its location.
The re-declaration lies in between opening and closing curly brackets, which act as barriers to the relevancy of these variables.
Limiting the accessibility of the variables declared inside of functions allows us to reuse variable names that may apply to separate parts of our code.
Locally scoped variables also prevent our code from having tens or hundreds of global variables floating around the global space unnecessarily.
Let's look at a slightly varied example…In this example, all we’ve changed is the location of the second console.
log, which is now inside the boundaries of the showScopeExample() function.
As seen in the console to the right, the first console.
log still prints “goodBoy” as expected.
Unfortunately, our second console.
log now prints “badDog” when we invoke showScopeExample() (poor pup).
This is because our second console.
log is now held within the boundaries of the curly brackets, and it will print information that is located within the same scope.
Finally, the third console.
log returns to printing “goodBoy.
” This is again because it does not have access to the local reassignment and resorts to the initial declaration.
It refers primarily to the use of the keyword this.
The value of this depends on where it is being invoked.
Invoking this in the global space will return the entire window object.
This is because the window object is the starting point of all the code we write.
Give it a try, and you’ll likely get something like this in response…“This” refers to the window object — the outermost context of our codeThe endless white text we get in return is the window object.
The first rule of this is that by default, it refers to the window object.
If you ever get the chance, you should explore the window object returned from invoking this in the global context.
But what happens if we invoke this somewhere other than the global context?.If we invoke this in the context of a new object, it will return that object, just as it returned the entire window object.
Let’s look at a simple example and then build on it.
Now “this” refers to the newContextObj — a more limited context than previouslyIn the example above, we’ve created a new object which we’ve named newContextObj.
When we invoke the method invokeThisInNewContext() it returns the entire newContextObj.
This is the same as when it returned the window object in our first example.
The only difference is that the window object is a very large and complex object, and our newContextObj is very small and simple.
The second rule of this is that when it is invoked in the context of an object, this will refer to that object.
Finally, the third rule of this is a bit more complicated.
For example, we could have a class that produces instances of a car object.
Despite the fact that the cars all have sizes, capacity, and engine types, these three things probably differ from car to car.
Below is an example of this being invoked in the context of an instance of ContextObj.
What we see in the example above is the invocation of the whereIsThis() method on our instance of ContextObj.
In this third and final example, the keyword this refers to this specific instance of ContextObj, no matter how many instances of ContextObj exist in our code.
ConclusionThese three examples attempt to summarize this in its most basic forms, and you’ll find in your own experiences that this becomes a very handy tool to have at your disposal.
The best way to become more familiar with concepts such as context and scope is simply experimenting with them.
Open your preferred text editor and start creating functions and object of your own.
Mess around with variable placement in your functions.
When do you have access to them and when do they return undefined?Create increasingly complex objects and invoke this in increasingly specific and limited contexts.
There is no better way to become comfortable coding than by getting your fingers on the keyboard and struggling through concepts, one at a time.
.. More details