JavaScript: differences between using var, let and const.

A close look and explanation at how to properly use the new ES6 JavaScript variable declaration keywords.

JavaScript Logo
JavaScript Logo

Introduction

With the advent of ES6 (EcmaScript2015), among the many new features, there have been introduced two new keywords to declare variables: let and const. Let's now look at them one by one to discover their differences using practical examples.

emoji 👉 Var

Everyone is already used to the good old var keyword, but a refresh is always a good idea.

About the var keyword:

  • Its enclosing scope is the Function scope;
  • It can be re-declared;
  • It can be re-assigned;
  • It hoists;
  • It does not suffer from TDZ (See: [1]).
//Using `var`.
function test(){

	console.log(x); // x === undefined <- It hoists.
	
	for( var z = 0; z < 3; z++ ){
	
		setTimeout(function(){
			console.log(z)
		}, 500); // 0 -> 3 | 1 -> 3 | 2 -> 3, It needs a closure to capture the value!
	
	}
	
	console.log(y); // y === undefined <- It's enclosing scope is the first function scope.
	
	if(true){

		var y = 1;
	
	}
	
	var x = 3;
	var x = 4; // It can be re-declared.
	x = 5; // It can be re-assigned.
	
	console.log(y); // y === 1
	console.log(z); // z === 3
	console.log(x); // x === 5
	
}

emoji 👉 Let

Let is a one of the new keywords and it introduces some really interesting features and gotchas:

  • Its enclosing scope is the Block scope;
  • It can't be re-declared;
  • It can be re-assigned;
  • It hoists;
  • It suffer from TDZ (See: [1]).
//Using `let`.
function test(){
	
	console.log(x); // Error! <- It hoists, but it can't be accessed (TDZ [1]).
	
	for( let z = 0; z < 3; z++ ){
	
		setTimeout(function(){
			console.log(z)
		}, 500); // 0 -> 0 | 1 -> 1 | 2 -> 2, Yey! emoji 🎉 It captures the values without the need of an new closure!
	
	}
	
	console.log(y); // Error! <- It is outside its scope!
	
	if(true){

		let y = 1;
	
	}
	
	let x = 3;
	let x = 4; // Error! <- It can't be re-declared!
	x = 5; // It can be re-assigned.
	
	console.log(y); // Error! <- It is outside its scope!
	console.log(z); // Error! <- It is outside its scope!
	console.log(x); // x === 5
	
}

emoji 👉 Const

Const is the other new keyword, and it is really straightforward:

  • Its enclosing scope is the Block scope;
  • It can't be re-declared;
  • It can't be re-assigned (See: [2]);
  • It hoists;
  • It suffer from TDZ (See: [1]).
//Using `const`.
function test(){

	console.log(x); // Error! <- It hoists, but it can't be accessed (TDZ [1]).
	
	for( const z = 0; z < 3; z++ ){ // Error! <- Can't be re-assigned!
	
		setTimeout(function(){
			console.log(z)
		}, 500);
	
	}
	
	console.log(y); // Error! <- It is outside its scope!
	
	if(true){

		const y = 1;
	
	}
	
	const x = 3;
	const x = 4; // Error! <- It can't be re-declared!
	x = 5; // Error! <- It can't be re-assigned! [2]
	
	console.log(y); // Error! <- It is outside its scope!
	console.log(z); // Error! <- It is outside its scope!
	console.log(x); // x === 3
	
}

Summary table

FeatureVarLetConst
Enclosing scopeFunction scopeBlock scopeBlock scope
Re-declarationYesNoNo
Re-assignmentYesYesNo ([2])
HoistsYesYesYes
Temporal Death Zone [1]NoYesYes

emoji 📔 Footnotes

[1] The TDZ (Temporal Death Zone) has been introduced along with let and const. In fact, the var declaration does not suffer from this issue. In particular the TDZ is the time that spans between the context creation (the variable is created and hoisted) and the assignment instruction (the variable has actually given a value). During this time a variable created with those keywords is inaccessible and therefore will throw and error trying to read it.

[2] You can't reassign a constant, but you can change its values in case it is an Object or an Array (See code below).

//Re-assigning `const`.
function test(){

	const MY_CONST_VAL = 1;
	const MY_CONST_ARR = [ 1, 2, 3 ];
	const MY_CONST_OBJ = { a: 1, b: 2, c: 3, d: { a: 1, b: 2 } };
	
	MY_CONST_VAL = 2;			// emoji 💥 Error! <- Can't be re-assigned!
	MY_CONST_VAL = [2];			// emoji 💥 Error! <- Can't be re-assigned!
	MY_CONST_VAL = {b: 2};		// emoji 💥 Error! <- Can't be re-assigned!
	
	MY_CONST_ARR = [2];		// emoji 💥 Error! <- Can't be re-assigned!
	MY_CONST_ARR[0] = 0;		// emoji 🎉 Works!
	MY_CONST_ARR[4] = 4;		// emoji 🎉 Works!
	MY_CONST_ARR.push(5)		// emoji 🎉 Works!
	
	MY_CONST_OBJ = {b: 2};		// emoji 💥 Error! <- Can't be re-assigned!
	MY_CONST_OBJ.a = 0;		// emoji 🎉 Works!
	MY_CONST_OBJ.d = 4;		// emoji 🎉 Works!
	delete MY_CONST_OBJ.d		// emoji 🎉 Works!
	
}

emoji 📚 Further readings

List of all the new ES6 features

The hoisting process

For updates, insights or suggestions, feel free to post a comment below! emoji 🙂


Responses

Latest from Web Engineering browse all

WebAssembly + Emscripten Notes. | cover picture
WebAssembly + Emscripten Notes.
Created December 25 2020.
My notes on learning WebAssembly and its integration with Emscripten.
Docker Notes. | cover picture
Docker Notes.
Created November 19 2020, updated December 25 2020.
My notes on learning Docker.
Algorithms in JavaScript: Bubblesort, Quicksort, Mergesort. | cover picture
Algorithms in JavaScript: Bubblesort, Quicksort, Mergesort.
Created September 17 2020, updated December 25 2020.
Explanation and implementation using JavaScript of some of the most popular sorting algorithms: Bubblesort, Quicksort and Mergesort.
×