const. So, let’s get started.
const. Each has its own properties and particularities. Let’s start by making a simple comparison table of the three keywords and then dive into the details.
Don’t worry if right now you’re not entirely sure what we mean by scope, hoisting, or any of the other attributes. We’re going to cover them in detail next.
Let’s work through the definitions by giving some examples of how scoping functions. Let’s say you define a variable
As you may expect the variable
message used in the
console.log would exist and have the value
Hello World. No doubts there, but what happens if we change a bit where we declare the variable:
Oops, it looks like we broke it, but why? Well, the
if statement creates a local block scope, and since we used ‘const’ the variable is only declared for that block scope, and cannot be accessed from the outside.
Let’s talk a bit more about block and function scopes.
A block is basically a section of code (zero or more statements) which is delimited by a pair of curly braces and may optionally be labeled.
As we already discussed the use of
const allows us to define variables that live within the block scope. Next, we’ll build very similar examples by using different keywords to generate new scopes:
Let’s explain this one as it may look a bit strange at first. In our outer scope, we were defining the variable
x1with a value of
x1. But don’t get confused, this is a brand new variable, which will only be available within that scope.
Same example now with a named scope:
The ‘while’ example, but don’t run this code below. I’ll explain why soon.
Can you guess what’s wrong with the code above? And what would happen if you ran it? Let me explain,
x3 as declared in the outer scope is used for the while comparison
x3 === 1, normally inside the while statement, I’d be able to reassign
x3 a new value and exit the loop. However as we’re declaring a new
x3 within the block scope, we cannot change
x3 from the outer scope anymore, and thus the ‘while’ condition will always evaluate to
true producing an infinite loop that will hang your browser, or if you’re using a terminal to run it on NodeJS will print a lot of
Fixing this particular code could be tricky unless you actually rename either variables.
So far in our example, we used
const, but exactly the same behavior would happen with
let. However, as we saw in our comparison table, the keyword
var is actually the function scope, so what does it mean for our examples? Well, let’s take a look:
Amazing! Even though we re-declared
x4 inside the scope, it changed the value to
2on the inner scope as well as the outer scope. And this is one of the most important differences between
var and is usually subject (in one way or another) for interview questions.
A function scope is in a way also a block scope, so
constwould behave the same way they did in our previous examples. However, function scopes also encapsulate variables declared with
var. But let’s see that continuing with our
Exactly as we expected it, and now with
In this scenario, ‘var’ worked the same way as
As we can see,
var declarations only exist within the function they were created in and can’t be accessed from the outside. But there’s more to it, as always JS has been evolving, and newer type of scopes have been created.
With the introduction of modules in ES6, it was important for variables in a module to not directly affect variables in other modules. Can you imagine a world where importing modules from a library would conflict with your variables? Not even JS is that messy. So by definition, modules create their own scope which encapsulates all variables created with
const, similar to the function scope.
So far we talked about different types of local scopes, let’s now dive into globalscopes.
A variable defined outside any function, block, or module scope has global scope. Variables in global scope can be accessed from everywhere in the application.
The global scope can sometimes be confused with module scope, but this is not the case. A global scope variable can be used across modules, though this is considered bad practice, and for good reasons.
How would you go about declaring a global variable? It depends on the context, it’s different on a browser than a NodeJS application. In the context of the browser, you can do something as simple as:
Or by using the window object:
There are some reasons you wanna do something like this, however, always be careful when you do it.
As you probably guessed by now, it’s possible to nest scopes, meaning you can create a scope within another scope, and it’s very common practice. Simply add an
if statement inside a function. So, let’s see an example:
In a way, we already made use of lexical scope, though we didn’t know much about it. Lexical scope simply means the other scopes have access to the variables defined in outer scopes.
Let’s see it with an example:
That looks stranger than what it is, so let’s explain it. The function
outerScope declares a variable
Juan and a function named
innerScope. The later does not declare any variables for its own scope but makes use of the variable
name declared in the outer function scope.
outerScope()gets called it returns a reference to the
innerScope function, which is later called from the outermost scope. When reading this code for the first time you may be confused as to why
console.log the value
Juan as we’re calling it from the global scope, or module scope, where
name is not declared.
This is what a normal flow would look like:
As expected that works, but what would you think of the following:
Wait wait wait…. what? As crazy as it sounds, since the function is assigned to memory before the code actually runs, the function
hoistedDisplayName is available before its actual definition, at least in terms of code lines.
Functions have this particular property, but also do variables declared with
var. Let’s see an example:
The fact the variable is “created” before its actual definition in the code doesn’t mean its value is already assigned, this is why when we do the
console.log(x8) we don’t get an error saying that the variable is not declared, but rather the variable has value
undefined. Very interesting, but what happens if we use
const? Remember in our table, they don’t share this property.
It threw an error.
Reassignment of variables
This topic covers specifically variables declared with the keyword
const. A variable declared with
const cannot be reassigned, meaning we can’t change its value for a new one, but there’s a trick. Let’s see some examples:
As we expected, we can’t change the value of a constant, or can we?
Did we just change the value of a
const value? The short answer is, no. Our constant
c2 references an object with a property
c2 is a reference to that object, that’s its value. When we do
c2.name we are really taking the pointer to the
c2 object and accessing the property from there. What we’re changing when we do
c2.name is the value of the property
name in the object, but not the reference stored in
c2, and thus
c2 remained constant though the property value is now different.
See what happens when we actually try to update the value differently:
Even though the object looks the same, we’re actually creating a new object
name: 'Gera' and trying to assign that new object to
c3, but we can’t as it was declared as constant.
This article was originally published on Live Code Stream by Juan Cruz Martinez (twitter: @bajcmartinez), founder and publisher of Live Code Stream, entrepreneur, developer, author, speaker, and doer of things.
Live Code Stream is also available as a free weekly newsletter. Sign up for updates on everything related to programming, AI, and computer science in general.
Pssst, hey you!
Do you want to get the sassiest daily tech newsletter every day, in your inbox, for FREE? Of course you do: sign up for Big Spam here.