Javascript Var and Let

After ES6 or around 2015/16, many programmers are saying stop using var and instead go for let and const. Well, I’m actually trying to understand whether I could just drop var or if there’s actually important differences between them. By the example below, one conclusion is that the way the JS Engine will act with var and let differs and it seems to have a relation to the execution context where it’s used on the code.

function using_var() {
  var arr = [];
  for (var i = 0; i < 3; i++) {
    arr.push(function () {
      console.log(i);
    })
  }
  return arr;
}
var f_var = using_var();
f_var[0]();
f_var[1]();
f_var[2]();
// output: 3,3,3
// the value of var i at the time of execution of f_var
// is the last i before exiting the for loop, which is 3

// 

function using_let() {
  var arr = []; // let arr = []; is ok too
  for (let i = 0; i < 3; i++) {
    arr.push(function () {
      console.log(i);
    })
  }
  return arr;
}
var f_let = using_let();
f_let[0]();
f_let[1]();
f_let[2]();
// output: 0,1,2
// the value of i at the moment of the for loop
// maybe it's like a IIFE? Immediately Invoked Function Expression?
// when using the let?

What you guys/girls think of the usage of var and let in JS?

var makes a variable exist for the whole existence of the function, which is called function scope.
let makes a variable exist for just the block that it’s contained in, and not before the let statement.
const is similar to let, except you aren’t allowed to redefine the variable to anything else either.

As const is the most restrictive, it leads to good programming discipline.
For example, without using let, you end up with better code structures instead.

Define the arr array using const

There’s no good reason to use var or let to define the arr variable. It’s not being redefined to anything else, which is normally a bad idea in the first place, so use const here. Any attempts to redefine arr either accidentally or intentionally, will result in an error giving you plenty of good warning about unexpected behaviour.

  const arr = [];

The for loop

Why are we iterating over three numbers. Hang on, it’s equal 0, to less than 3, which doesn’t include 3. So that’s 0, 1, and 2. Yes, three numbers. Already lots of mental overhead is used just to check that information.

Instead of that, we can make the arr array of a certain size and use fill to give it some starting values.

const arr = new Array(3).fill(0);

We can now use the forEach method to iterate through all fields of that array.

  arr.forEach(function (item, i) {
    arr[i] = function () {
      console.log(i);
    };
  });

The full code that uses const instead of let, is as follows:

function using_const() {
  const arr = new Array(3).fill(0);
  arr.forEach(function (item, i) {
    arr[i] = function () {
      console.log(i);
    };
  });
  return arr;
}
var f_const = using_const();
f_const[0]();
f_const[1]();
f_const[2]();
// output: 0,1,2

The rest of what follows is bonus, attempting to improve things further.

Avoid reassigning to the array

Bad things are easier to occur when you change variables and state, so it’s usually better to avoid reassigning variables when you can.

In this case, instead of using forEach to reassign to each array index, we can instead use the map method to create a new array, and return that instead.

  return arr.map(function (item, i) {
    return function () {
      console.log(i);
    };
  });

Improve the array assignment

Currently we are creating an arr variable using both new and fill. We can instead use the Array.from method, to create an array of a desired size.

const arr = Array.from({length: 3});

Fill the array

Array.from also has a second function parameter, for what to fill the array with.

const arr = Array.from({length: 3}, 0);

But we don’t want to fill it with zero. We want to fill it with functions that know what value to return. We can do that when we initialize the array and avoid the double step of using arr.map afterwards.

  const arr = Array.from({length: 3}, function (item, i) {
    return function () {
      console.log(i);
    };
  });

The full const code

The full and improved code that uses const is:

function using_const() {
  const arr = Array.from({length: 3}, function (item, i) {
    return function () {
      console.log(i);
    };
  });
  return arr;
}
var f_const = using_const();
f_const[0]();
f_const[1]();
f_const[2]();
// output: 0,1,2

What if we avoided const?

Because we are assigning a variable and are then immediately returning it, we don’t need the assignment at all.

function using_none() {
  return Array.from({length: 3}, function (item, i) {
    return function () {
      console.log(i);
    };
  });
}
var f_none = using_none();
f_none[0]();
f_none[1]();
f_none[2]();
// output: 0,1,2

Summary

The default preference should be to use no variable at all.
Use const when it helps to improve the understandability of the code.
When you are forced to reassign to a variable, use let. The existence of that let variable becomes a blight on the landscape, prompting you to improve your code so that it reads and works better without it.

Info pages referred to are:

Note: Normally I name all functions in my code to make it easier to understand, but have avoided doing that here in the interest of brevity.

2 Likes