The Difference Between var, let and const in JavaScript and Best Practices

Introduction

Programming has always included the definition of data, manipulation of data, and finally displaying data. Data can be represented as bits of information that we can alter in computer programs. Since memory locations aren't very human-readable, and change through time - we've started annotating variable data, with human-readable signifiers, which we can call on, to indirectly point to data in-memory.

These signifiers are commonly called variables or reference variables.

Variables are, essentially, pointers or references to some data in a machine's memory, and the pointer can dynamically be changed to reflect the true state of the data we've "labeled".

Note: Commonly and colloquially, it's said that "variables store data" and that they're "containers for data". This is technically incorrect, and stems from a blurred semantic boundary - it's unclear whether people refer to reference variables or objects in-memory. (Reference) Variables are pointers, and they point to objects in the machine's memory - where the data is stored. The colloquial terms are commonplace enough that you'll find them present in documentation, but it's worth keeping object-memory-allocation at least in the back of your head.

Prior to the release of ES2015 (ES6), JavaScript variables were only declared using the var keyword; however, with the introduction of ES6, new ways to declare variables, let and const, were introduced. This oftentimes brings up questions - mainly as to which keyword should be used, and when:

var english = "Hello there!";
let french = "Bonjour!";
const german = "Hallo!";

In this guide, we will explore the difference between the three various ways to declare variables in JavaScript - var, let and const, their scopes and when to choose which.

What is Scope in JavaScript?

Scope is an important concept to grasp in order to write code in most programming languages, and plays an important part in choosing which variable keyword you'll want to use. Scope defines variable availability. In JavaScript, we have two scopes: global and local.

  • Global Scope: Variables declared outside any code block or function are known as global variables because they have a global scope, and can be referenced from any function or block.

Note: In a JavaScript document, only one global scope exists.

Suppose you have a script file. Again, any variable declared outside any function or block is globally scoped:

// Initialized outside of function or block
var name = "John Doe";
function logName() {
  console.log(name);
};
    
logName();

In the example above, name is accessible within the logName() function, as it has a global scope. It exists in the context of the application, and the logName() function can call on that context!

  • Local Scope: Variables declared within any code block or function are known as local variables, because they have a local scope. They can be referenced only within the code blocks or functions in which they're defined.
function logName() {
  // Initialized within a function or block
  var name = "John Doe";
  var id = 1;
  console.log(name);
};
    
function logId() {
  console.log(id);
}
    
logId();

This results in:

error: Uncaught ReferenceError: id is not defined

How come? id is defined - but it isn't defined in the scope of the logId() function. As far as the function is concerned - no id exists. It starts by checking whether there's a locally scoped variable. Since there's none, it checks whether there's a globally scoped variable. If not - id is not defined from the context of logId()!

With the primer/reminder out of the way - let's take a look at how var, let and const depend on the scope, and when each should be used!

The var Keyword in JavaScript

In JavaScript, var is a reserved keyword which is followed by a reference variable name. The name defined after the keyword can then be used as a pointer to the data in-memory.

Using var is the oldest method of variable declaration in JavaScript. Let's declare a variable and initialize it by assigning a value to it using the assignment operator (=):

// Declaration and initialization
var name = "John Doe";

Alternatively, you can break this down into two steps - variable declaration (what it is), and variable initialization (assigning a value to it):

// Declaration
var name;
// Initialization
name = "John Doe";

Note: In strongly-typed languages, such as Java, for a long time, you'd define the type of the variable during declaration, and during initialization, you could only assign a value fitting that type. Since Java 10 - a var keyword has been added, which is type-agnostic and infers the type during runtime.

Scope of var

When defined within a function - any var is restricted to that function. When defined outside of a function, a var is global:

Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

  var firstName = "John";
  
  function checkLastName() {
    var lastName = "Doe";
  }

We have two declarations in the preceding example: firstName is globally scoped because it's defined outside a function, and lastName is locally/function scoped because it's defined within a function:

var firstName = "John";
  
function checkLastName() {
    var lastName = "Doe";
    console.log(lastName); // "Doe"
    console.log(firstName); // "John"
}
  
checkLastName();
console.log(lastName); // Uncaught ReferenceError: lastName is not defined

So far so good. However - var has an issue.

The Issue with var

var is not block-scoped. When you declare a variable within a code block, using curly braces ({}), its scope "flows out" of the block! For instance:

var name = "John Doe";
  
var someBool = true;
if (someBool) {
  var name = "Daniel Joan";
}
  
console.log(name);

The name that points to "John Doe" is global, and the name that points to "Daniel Joan" is defined within a block. However, when we try printing the name that's within scope, we run into:

Daniel Joan

var is not block-scoped. We may think that we've defined a local var name to point to "Daniel Joan", but what we've done in reality is overwrite the var name that points to "John Doe".

Declaring variables using the var declarations everywhere in your code can lead to confusion, overwriting of existing global variables and by extension - bugs, just as we saw in the code snippet.

This is where let and const kick in!

The let Keyword in JavaScript

The let declaration was introduced with ES6 and has since become the preferred method for variable declaration. It is regarded as an improvement over var declarations and is block-scoped (variables that can be accessed only in the immediate block), circumventing the main issue that can arise with using var.

Scope of let

A variable defined with the let keyword has a scope limited to the block or function in which it is defined:

let firstName = "John";
let lastName = "Doe";

let someBool = true;
if(someBool){
    let firstName = "Jane";
    console.log(firstName);
}
  
console.log(firstName);

This time around - the firstName referring to "Jane" and the firstName referring to "John" don't overlap! The code results in:

Jane
John

The firstName declared within the block is limited to the block in scope and the one declared outside the block is available globally. Both instances of firstName are treated as different variable references, since they have different scopes.

The const Keyword in JavaScript

The const declaration was introduced with ES6, alongside let, and it is very similar to let. const points to data in memory that holds constant values, as the name implies. const reference variables cannot be reassigned to a different object in memory:

const name = "John";
const name = "Jane";

This results in:

Uncaught SyntaxError: Identifier 'name' has already been declared

Scope of const

The scope of a variable defined with the const keyword, like the scope of let declarations, is limited to the block defined by curly braces (a function or a block). The main distinction is that they cannot be updated or re-declared, implying that the value remains constant within the scope:

const name = "John";
name = "Doe";
  
// Uncaught TypeError: Assignment to constant variable. 

Good Coding Conventions

So, what does this all mean, and which should you choose, other than the obvious requirements to avoid bugs? This can actually be boiled down to a couple of good practices:

  • const is preferred to let, which is preferred to var. Avoid using var.
  • let is preferred to const when it's known that the value it points to will change over time.
  • const is great for global, constant values.
  • Libraries are typically imported as const.

When importing a library and instantiating it - you don't want to be able to reassign the instance to something else, since you'd enter a slippery slope of "using the library", whereas, something else is "slipping code in" under the hood.

For instance, if you were to require() a library such as Axios, you're conceivably wanting to use its API. However, there's nothing preventing you (or someone else) to switch out the axios instance with something else if you haven't used const to declare it:

let axios = require('axios');
axios.get('some_url').then(someFunction());

axios = "Totally not a string!"
axios.get('some_url').then(someFunction()); // String has no method `get()`

By having axios be const - this issue is avoided. Additionally, you can define global constants, which can be used as configuration constants:

const WIDTH = 1920;
const HEIGHT = 1080;

Conclusion

In this guide, we've explored the progression of variable declaration in JavaScript, from the original var to the newer let and const.

We've explored Scopes in JavaScript and how the different declaration signifiers affect the scope of a variable in code, noting a glaring issue with using var. Finally, we've explored some good practices, noting when to use which keyword.

Last Updated: May 22nd, 2023
Was this article helpful?

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

Joel OlawanleAuthor

Frontend Developer & Technical Writer

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms