Click here to view Part II: Understanding fat arrow functions
This article is designed as a “get started” read for beginner to intermediate developers who wish to gain a better understanding of ES6 variables.
As part of my “Getting to Grips with ES6” series, I aim to create a reference containing straight forward explanations ordered in short sections to help us understand and apply these concepts directly to our current development processes.
Written by Andrew Hill. You can find me on LinkedIn, Twitter, Instagram, and GitHub.
While the var
statement is not new to ES6, I strongly recommend reading through this refresher to help us better understand the concepts that the const
and let
statements introduce.
At its core, the var
statement allows us to define, update and redefine variables. Variables declared with var
are considered function scoped.
We can define and update variables declared with var
without any errors.
var test = 100;
console.log(test);// Output: 100
test = 200;
console.log(test);// Output: 200
We can also define an entirely new variable with the same name to override our previous variable with no errors.
var test = 100;
console.log(test);// Output: 100
var test = 200;
console.log(test);// Output: 200
Variables defined using var
are scoped as follows:
Consider the following example:
function scopeTest() {var test = 100;console.log(test);}
scopeTest();// Output: 100
The test
variable is considered a local variable, function scoped to the scopeTest()
function. We are able to access the value stored in the variable test
as both the variable declaration and the console.log()
exist within the same scopeTest()
function.
Using a modified version of this example allows us to illustrate how this variable is not accessible outside of the function it is scoped to:
function scopeTest() {var test = 100;}
scopeTest();
console.log(test);// Output: [Error] 'test' is not defined.
We are also allowed to update a variable at a higher scope to gain access to the value outside of the function. For reasons beyond the scope of this article, this is often considered bad practice and should be avoided unless absolutely necessary.
var test;
function scopeTest() {test = 100;}
scopeTest();
console.log(test);// Output: 100
So why bring in the new const
and let
statements in ES6? Because any variable defined outside of a function using _var_
is globally scoped.
Global scoping is bad as it introduces:
The let
statement allows us to define and update variables much in the same way the var
statement does, but it does not allow us to redefine variables that are already defined in the same scope. Variables defined with let
are also considered block scoped.
We can define and update variables declared with let
without any errors.
let test = 100;
console.log(test);// Output: 100
test = 200;
console.log(test);// Output: 200
Attempting to define a new variable with the same name as our previously defined let
variable is prohibited and results in errors.
let test = 100;
console.log(test);// Output: 100
let test = 200;// Output: [Error] Identifier 'test' has already been declared.
console.log(test);// Output: 100
The const
statement allows us to define variables only. Unlike let
which was made to be updated, const
prohibits updating variables entirely. Furthermore, like let
, const
prohibits the redefining of variables that have already been defined in the same scope. Variables defined with const
are considered block scoped.
We can define const
variables but are prohibited from updating the values assigned to the variable. Attempting to update a const variable will result in errors.
const test = 100;
console.log(test);// Output: 100
test = 200;// Output: [Error] Assignment to constant variable.
console.log(test);// Output: 100
Attempting to define a new variable with the same name as our previously defined const
variable is prohibited and results in errors.
const test = 100;
console.log(test);// Output: 100
const test = 200;// Output: [Error] Identifier 'test' has already been declared.
console.log(test);// Output: 100
There is a growing misconception that const
is entirely immutable meaning you can never update an objects properties once it is assigned to a const
variable. When it comes to objects and const
, you cannot redefine the const
variable, but you are allowed to update the properties of the object.
In the below example, we attempt to assign a new object to the test
variable. As previously covered, this is not allowed and we encounter errors.
const test = {milliseconds: 1862,createdBy: 'Andrew Hill',}
test = {milliseconds: 1862,createdBy: 'Jane Doe',}
// Output: [Error] Assignment to constant variable.
console.log(test);// Output: Object { milliseconds: 1862, createdBy: 'Andrew Hill' }
However, in this example we are able to update the properties of the test
variable without any problems.
const test = {milliseconds: 1862,createdBy: 'Andrew Hill',}
test.createdBy = 'Jane Doe';
console.log(test);// Output: Object { milliseconds: 1862, createdBy: 'Jane Doe' }
If you are looking for “truly” immutable objects, take a look at the [Object.freeze()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)
method which prevents new properties from being added, existing properties from being removed, and prevents existing properties, their enumerability, configurability, and writability, from being changed.
Variables defined using const
and let
are considered block scoped, meaning they are available to you inside the code block in which they are defined. A JavaScript code block is anything that falls within curly braces {}
. Objects and functions both contain blocks and it is perfectly valid to have a block exist on its own.
Consider the following example. Note that we are using let
in the below example, but the same rules apply to the way const
is scoped:
function scopeTest() {let test = 100;console.log(test);}
scopeTest();// Output: 100
In this example, the test
variable is considered a local variable, scoped to the block created by the scopeTest()
function. We are able to access the value stored in the variable test
as both the variable declaration and the console.log()
exist within the same scopeTest()
function block.
Using a modified version of this example allows us to illustrate how this variable is not accessible outside of the function block it is scoped to.
function scopeTest() {let test = 100;}
scopeTest();
console.log(test);// Output: [Error] test is not defined.
Multiple variables can be defined with the same name using const
and let
so long as they do not fall within the same block. Doing this will result in two entirely different variables existing with the same name at different scopes.
let test = 100;
console.log(test);// Output: 100
function scopeTest() {let test = 200;
console.log(test);// Output: 200}
console.log(test);// Output: 100
So what should you use when? There are some differing opinions on this matter which you can dig into with a few quick Google searches. Ultimately, I choose to use them in the way Mathias Bynens describes in his article:
const
for all variable declarations by default.let
only if rebinding is needed.var
should not be used in ES6Thanks for reading. If you liked this article please consider supporting future installations of this series by recommending it. 👏
Click here to view Part II: Understanding fat arrow functions