Modern JavaScript syntax - ES6 const variables

|4 min read|
Teklog
Teklog


Introduction

ES6 brought lots of new features. Among them is support for constants. Instead of using var while declaring variables, you are now free to choose between const and let.

In this tutorial I will focus primarily on const and its "immutability" quirks, while let will be tackled in the following one. Without further ado, let's start it off by going through the handful of examples.

Assumptions

  • Familiarity with Codepen, JSFiddle or JSBin
  • Familiarity with Browser Developer Tools

Example I - Primitive

const PI = 3.14;

// Not possible, because initial value is missing
// const PI;

// Not possible to reassign
// PI = 3.12;

// Not possible to redeclare
// var PI = 3.14159265359

// Possible in IIFE, because it is in different context
(function() {
  const PI = 3.14159265359;
  // Will output 3.14159265359
  console.log(PI);
})();

// Possible, because it's in different block scope
if (true) {
 const PI = 3.14159;
 // Will output 3.14159
 console.log(PI);
}

// Not possible, because var variable gets hoisted 
// if (true) { var PI = 3.14159; }

// Will output 3.14
console.log(PI);

As you see, you must assign an initial value to const variable. Additionally, you cannot redeclare it, nor assign a new value, unless it's in different scope. Similar rules apply to variables of type string, integer, float and so on, as well as to variables holding a function expressions. (const f = function() { return 'sth'; })

Example II - Array

const PLANETS = ['Mercury', 'Venus', 'Earth', 'Mars'];

// Not possible to reassign
// PLANETS = ['Mercury'];

// Not possible to redeclare
// var PLANETS = [];

PLANETS[5] = 'Saturn';
delete PLANETS[0];
// Will output [undefined, 'Venus', 'Earth', 'Mars', undefined, 'Saturn'] 
console.log(PLANETS);

PLANETS.push('Jupiter');
// Will output [undefined, "Venus", "Earth", "Mars", undefined, "Saturn", "Jupiter"]
console.log(PLANETS);

PLANETS.pop();
PLANETS.pop();
PLANETS.pop();
PLANETS.shift();
// Will output ["Venus", "Earth", "Mars"]
console.log(PLANETS);

PLANETS.unshift('MERCURY');
// Will output ["MERCURY", "Venus", "Earth", "Mars"]
console.log(PLANETS);

PLANETS.length = 6;
// Will output ["MERCURY", "Venus", "Earth", "Mars", undefined, undefined]
console.log(PLANETS);

PLANETS.length = 1;
// Will output ["MERCURY"]
console.log(PLANETS);

As you see, you cannot reassign anything to PLANETS nor redeclare it, pretty similar as for primitives. However you can modify, add or delete elements inside this array, which may seems a bit awkward at first.

Example III - Object

const PERSON = {
  name: 'John',
  surname: 'Doe',
  age: 30
};

// Not possible to reassign
// PERSON = {};

// Not possible to redeclare
// var PERSON = {};

PERSON['name'] = 'Adam';
PERSON['children'] = 1;
delete PERSON['age'];
// Will output Object { children=1, name="Adam", surname="Doe" }
console.log(PERSON);

Like arrays, you cannot reassign anything to PERSON object nor redeclare it, but you can freely modify, add or delete any properties inside this object.

If you truly need an immutable object or array, you may use Object.freeze as shown below.

const PERSON = Object.freeze({
  name: 'John',
  surname: 'Doe',
  age: 30,
  birthday: Object.freeze({
    day: 3,
    month: 8
  })
});

PERSON['name'] = 'Adam';
PERSON['birthday']['year'] = 1980;

// Will output Object {name="John", surname="Doe", age=30, Object {day=3, month=8}}
console.dir(PERSON);
const CARS = Object.freeze([
  Object.freeze(['BMW 3', 'BMW 5']),
  ['VW Golf', 'VW Toureg']
]);

// Not possible
// CARS[0].push('BMW 7');

CARS[1].push('VW Polo');
// Will output [["BMW 3", "BMW 5"], ["VW Golf", "VW Toureg", "VW Polo"]]
console.log(CARS);

Keep in mind though that freeze is a shallow operation, so you need to repeat it in all of your child objects and arrays.

Alternatively, you could use Object.seal that allows changes of the existing properties, but forbids to add new ones.

ES5 equivalent

Object.defineProperty(window, "PI", {
  value: 3.141593,
  enumerable: true,
  writable: false,
  configurable: false
})

Once you run this, you actually won't be able to undo this action.

  • it's forbidden to redefine window.PI using Object.defineProperty again
  • it's impossible to delete it via delete window.PI

It turns out you can only refresh your page to get this value cleaned up. Feel free to learn more about Object.defineProperty.

Summary

Variables defined as constants work predictable and well with primitives as strings, integers or floats. However they should be used with caution when applied to arrays or objects. People mostly assume const variables as immutable, but in the world of JavaScript the reality is different.

There is lots of documents, tutorials, videos and books related to ES6 constants, including the following:

If you stumbled across any other interesting materials, please let me know via Twitter.

I tend to declare const variables using capital letters. Additionally, I default to const every time I declare a new variable. If I need to reassign it later on, I simply change it to let, therefore trying to stay away from var variables.

Code samples