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.