A lot of shiny new features came out with ES2015 (ES6). And now, since it’s 2020, it’s assumed that a lot of JavaScript developers have become familiar with and have started using these features.
While this assumption might be partially true, it’s still possible that some of these features remain a mystery to some devs.
One of the features that came with ES6 is the addition of let
and const
which can be used for variable declaration. The question now is, what makes them different from our good ol’ var
which we’ve been using? If you are still not clear about this, then this article is for you.
In this article, we’ll cover the differences between var
, let
, and const
. we’ll discuss var
, let
and const
with respect to their scope, use, and hoisting. You’ll also learn some prescriptive rules to know when to choose one over the other. As you read, take note of the differences between them that I’ll point out.
Before we can understand how var
and let/const
differ we need to understand a computer science-y concept called scope.
In JavaScript there’s two kinds of scope: function-scope and block-scope.
function myFn() {
var foo = 'peekaboo!';
console.log(foo); // 'peekaboo!'
}
console.log(foo); // ReferenceError: foo is not defined
Using var
, variables are function-scoped because their visibility is limited to the function. When you try to use it outside of the function, you’ll get an error.
if (true) {
var foo = 'peekaboo!';
let bar = 'i see u';
const baz = 'baby blue!';
console.log(foo); // 'peekaboo!';
console.log(bar); // 'i see u';
console.log(baz); // 'baby blue!';
}
console.log(foo); // 'peekaboo!';
console.log(bar); // ReferenceError: bar is not defined
console.log(baz); // ReferenceError: baz is not defined
Notice the visibility of foo
isn’t limited by the if-statement block. However, both bar
and baz
are limited in visibility to the block of code.
This concept of scope is the most prominent distinction between the old-fashioned var
and modern let/const
.
A block of code is the code between curly braces in JavaScript.
Before the advent of ES6, var
declarations ruled. There are issues associated with variables declared with var
though. That is why it was necessary for new ways to declare variables to emerge. First though, let us get to understand var
more before we discuss those issues.
Scope essentially means where these variables are available for use. var
declarations are globally scoped or function/locally scoped.
The scope is global when a var
variable is declared outside a function. This means that any variable that is declared with var
outside a function block is available for use in the whole window.
var
is function scoped when it is declared within a function. This means that it is available and can be accessed only within that function.
To understand further, look at the example below.
var greeter = "hey hi";
function newFunction() {
var hello = "hello";
}
Here, greeter
is globally scoped because it exists outside a function while hello
is function scoped. So we cannot access the variable hello
outside of a function. So if we do this:
var tester = "hey hi";
function newFunction() {
var hello = "hello";
}
console.log(hello); // error: hello is not defined
We’ll get an error which is as a result of hello
not being available outside the function.
This means that we can do this within the same scope and won’t get an error.
var greeter = "hey hi";
var greeter = "say Hello instead";
and this also
var greeter = "hey hi";
greeter = "say Hello instead";
Hoisting is a JavaScript mechanism where variables and function declarations are moved to the top of their scope before code execution. This means that if we do this:
console.log (greeter);
var greeter = "say hello"
it is interpreted as this
var greeter;
console.log(greeter); //greeter is undefined
greeter = "say hello"
So var
variables are hoisted to the top of their scope and initialised with a value of undefined.
There’s a weakness that comes with var
. I’ll use the example below to explain:
var greeter = "hey hi";
var times = 4;
if (times > 3) {
var greeter = "say Hello instead";
}
console.log(greeter) //"say Hello instead"
So, since times > 3
returns true, greeter
is redefined to "say Hello instead"
. While this is not a problem if you knowingly want greeter
to be redefined, it becomes a problem when you do not realise that a variable greeter
has already been defined before.
If you have used greeter
in other parts of your code, you might be surprised at the output you might get. This will likely cause a lot of bugs in your code. This is why let
and const
are necessary.
There’s other nuances between var
and let/const
so let’s explore a few code snippets to understand them better.
// for-loop
for (var i = 0; i < 3; i++) {
console.log(i);
}
console.log(i);
What do you think the output of this code is?
// 0
// 1
// 2
// 3
The variable i
is accessible outside of the for-loop. This is expected since variables defined with var
are only inaccessible outside of a function definition.
var
Using var
you can reassign it with a new value.
function myFn() {
var foo = 1;
foo = 30;
var foo = 101;
console.log(foo);
}
myFn();
What’s the output of myFn()
?
// 101
let
is now preferred for variable declaration. It’s no surprise as it comes as an improvement to var
declarations. It also solves the problem that was raised in the last subheading. Let’s consider why this is so.
A block is a chunk of code bounded by {}. A block lives in curly braces. Anything within curly braces is a block.
So a variable declared in a block with let
is only available for use within that block. Let me explain this with an example.
let greeting = "say Hi";
let times = 4;
if (times > 3) {
let hello = "say Hello instead";
console.log(hello);//"say Hello instead"
}
console.log(hello) // hello is not defined
We see that using hello
outside its block (the curly braces where it was defined) returns an error. This is because let
variables are block scoped .
Just like var
, a variable declared with let
can be updated within its scope. Unlikevar
, a let
variable cannot be re-declared within its scope. So while this will work,
let greeting = "say Hi";
greeting = "say Hello instead";
this will return an error.
let greeting = "say Hi";
let greeting = "say Hello instead";//error: Identifier 'greeting' has already been declared
However, if the same variable is defined in different scopes, there will be no error.
let greeting = "say Hi";
if (true) {
let greeting = "say Hello instead";
console.log(greeting);//"say Hello instead"
}
console.log(greeting);//"say Hi"
Why is there no error? This is because both instances are treated as different variables since they have different scopes.
This fact makes let
a better choice than var
. When using let
, you don’t have to bother if you have used a name for a variable before as a variable exists only within its scope.
Also, since a variable cannot be declared more than once within a scope, then the problem discussed earlier that occurs with var
does not happen.
Just like var
, let
declarations are hoisted to the top. Unlike var
which is initialised as undefined
, the let
keyword is not initialised. So if you try to use a let
variable before declaration, you’ll get a Reference Error
.
let
outside of a for-loop// for-loop
for (let i = 0; i < 3; i++) {
console.log(i);
}
console.log(i);
What do you think is the output?
// 0
// 1
// 2
// ReferenceError: i is not defined
let
Using let
you can reassign variables, but its syntax is more strict than var
.
function myFn() {
let foo = 1;
foo = 30;
// let foo = 101; // 🙅♀️ can't use "let" keyword again
foo = 101;
console.log(foo);
}
myFn();
console.log(foo);
What’s the output of myFn()
?
// 101
// ReferenceError: foo is not defined
Variables declared with the const
maintain constant values. const
declarations share some similarities with let
declarations.
Like let
declarations, const
declarations can only be accessed within the block they were declared.
This means that the value of a variable declared with const
remains the same within its scope. It cannot be updated or re-declared. So if we declare a variable with const
, we can neither do this:
const greeting = "say Hi";
greeting = "say Hello instead";//error : Assignment to constant variable.
nor this:
const greeting = "say Hi";
const greeting = "say Hello instead";//error : Identifier 'greeting' has already been declared
Every const declaration, therefore, must be initialised at the time of declaration.
This behavior is somehow different when it comes to objects declared with const
. While a const
object cannot be updated, the properties of this objects can be updated. Therefore, if we declare a const
object as this:
const greeting = {
message : "say Hi",
times : 4
}
while we cannot do this:
const greeting = {
words : "Hello",
number : "five"
}//error : Assignment to constant variable.
we can do this:
greeting.message = "say Hello instead";
This will update the value of greeting.message
without returning errors.
Just like let
, const
declarations are hoisted to the top but are not initialised.
So just in case you missed the differences, here they are:
var
declarations are globally scoped or function scoped while let
and const
are block scoped.var
variables can be updated and re-declared within its scope; let
variables can be updated but not re-declared; const
variables can neither be updated nor re-declared.var
variables are initialised with undefined
, let
and const
variables are not initialised.var
and let
can be declared without being initialised, const
must be initialised during declaration.The keyword const
is an abbreviation for constant. Similar to let
, it’s block-scoped, however, you can’t reassigned it.
What do you think is the output of this code?
const myBoolean = true;
if (myBoolean) {
const turtles = [
'leonardo',
'donatello',
'michaelangelo',
'raphael'
];
// turtles = turtles.concat('Shredder'); // 🙅♀️ this would throw an error
console.log(turtles);
}
console.log(turtles);
// ['leonardo', 'donatello', 'michaelangelo', 'raphael']
// ReferenceError: turtles is not defined
Got any question or additions? Please let me know.
Thank you for reading :)
#javascript #web-development