Objective: By the end of this checkpoint, you will have better understanding of ‘variable scopes’.
By variable scope, we are talking about the visibility of variables in our code; or in other words, which parts of the code can access and modify a variable.
const statements for anyone who is not already familiar with these.
Let’s begin by considering global scope. Globally declared variables can be accessed and modified anywhere in the code (well almost, but we will come to the exceptions later).
Global variables are declared in the code outside of any function definitions, in the top-level scope.
In this example,
a is a global variable; it is therefore readily available in any function within our code. So here we can output the value of
a from the method
alpha. When we call
alpha, the value
Fred Flinstone is written to the console.
When declaring global variables in a web browser, they are also properties of the global
window object. Take a look at this example:
b can be accessed/modified as the property of the
window.b. Of course it isn’t necessary to assign the new value to
b via the
window object, this is just to prove a point. We are more likely to write the above as:
Be careful when using global variables. They can lead to unreadable code that is also difficult to test. We’ve seen many developers become stuck with global variables trying to discover where the variable’s value is being changed within our codebase causing unexpected bugs. It is far better to pass variables as arguments to functions than rely on globals. For those reasons, global variables should be used sparingly, if at all.
If you really need to use the global scope it is a good idea to namespace your variables so that they become properties of a global object. For example, create a global object named something like globals or app.
If you are using NodeJS then the top-level scope is not the same as the global scope. If you use
var foobar in a NodeJS module it is local to that module. To define a global variable in NodeJS we need to use the global namespace object,
It’s important to be aware that if you do not declare a variable using one of the keywords
const in your codebase, then the variable is given a global scope.
It’s a good idea to always initially declare variables with one of the variable keywords (particularly with
const, more on that below). This way we are in control of each variable’s scope within our code.
Now we come to the local scope.
Variables declared within a function are scoped locally to that function. In the examples above, both variables
c are local to their respective methods.
b is locally scoped to the function
delta as it is being declared as an argument of the method, only the value of
a is being passed to the function not the variable itself;
c is declared as a local variable of
epsilon inside the function. However, what if we have the following code? what does this write to the console?
The answer is
zeta, we are declaring a new variable
d that has a local scope. When using
const that will help avoid these issues going forward. So let’s take a look at how we can use
let as block scope variables.
With the arrival of ES6 a few years ago came two new keywords for declaring variables:
const. Both keywords allow us to scope to a block of code, that’s anything between two curly braces,
let is seen by many as a replacement to the existing
var. However, this isn’t strictly true as they scope variables differently. Whereas a
var statement allows us to create a locally scoped variable,
let scopes a variable to the block. Of course a block can be a function allowing us to use
let pretty much as we would have used
a is block scoped to the function
eta. We can also scope to conditional blocks and loops. The block scope includes any sub-blocks contained within the top-level block that the variable is defined.
In this example,
b is block scoped to the
for loop (which includes the conditional block inside it). So it will output the odd numbers
3 and then throw an error because we can’t access
b outside the loop that it was scoped to.
What about our strange little function
let what happens?
d is block scoped to the conditional, but does this mean hoisting is not happening here? No, when we use either
var, the hoisted variables are intiated with
const variables remain uninitiated. They exist in a temporal dead zone.
Let’s take a look what happens when we attempt to access a block scoped variable before it is initiated.
theta will output
undefined for the locally scoped variable
e and throw an error for the block scoped variable
f. We cannot use
f until after it is initiated, in this case where we set its value as ‘Road Runner’.
There is one other important difference between
var that we need to mention before moving on. When we use
var in the very top level of our code, it becomes a global variable and is added to the
window object in browsers. With
let, whilst the variable will become global in the sense that it is block scoped to the entire codebase, it does not become a property of the
We previously mentioned
const in passing. This keyword was introduced alongside
let as part of ES6. In terms of scope, it works the same as
In this example,
a is scoped to the
if statement so that it can be accessed inside the conditional, but is
undefined outside of it.
let, variables defined by
const cannot be changed through re-assignment.
However, when working with arrays or objects, things are a little different. We still cannot re-assign, so the following will fail:
But we can modify a
const array or object unless we use
Object.freeze() on the variable to make it immutable.
We kind of saw this earlier when looking at hoisting. But let’s take a look at what happens when we redeclare a variable in the local scope that already exists globally.
a. But inside the function
iota, we create a new local variable
a. The new local variable does not modify the global variable. But if we want to access the global value from within the function, we’d need to use the global
For us, this code would be much easier to read if we’d used a global namespace for our global variable and rewrite our function to use block scope:
Hopefully by now the following code should behave as you’d expect:
Code like this isn’t particularly readable. But the block scoped variable is a new variable accessible only within the block it is defined. Modifying the block variable will have no effect on the locally scoped variable outside of the block. The same will happen if we use
let to declare all variants of the variable
a. So we can rewrite the example like this:
const statements for declaring variables. With the arrival of ES6, we can now use
const where we once would have used
var. Unfortunately, for many, this is still the approach they are now taking.
Does this mean that
var is redundant? Well, there is no right or wrong answer. We still like to use
var for defining global variables at the top-level. However, we use global variables sparingly and like to create a global namespace as discussed earlier for the few cases where these are needed. Otherwise, for any variables whose values will never change, we’d use
const and, for everything else,
At the end of the day, it is up to you on how you declare your variables. But hopefully now you have a better understanding on how they will scope in your code.