JavaScript - Variables

post javascript beginning javascript

This article is a part of the Beginning JavaScript series.

Declaring Variables #

Declaring variables requires, at a minimum, two parts: a keyword, which indicates a variable declaration statement (except when you don't provide a keyword, see below), and an identifier - also referred to as a name - for the variable. JavaScript variables may be declared using one of three available keywords - var, let, and const. Given these three methods for declaring variables, what are the differences between them, and when should one be used over the other two?

While var has been used since the beginning of the language, both let and const were only implemented in ES6 (2015). Before to ES6, let and const were considered future reserved words. The following sections will provide a little more information on the differences between the three keywords.

Note: Because JavaScript is a loosely-typed and dynamic language, variables can be assigned values of any data type.

var #

The original variable declaration keyword in JavaScript is var. Variables declared with var:

The var keyword allows for the flexible declaration of variables, but perhaps it's a little too flexible. For example, the following snippet demonstrates using the keyword var to declare a variable named someVariable:

var someVariable; // someVariable declared and initialized to undefined
someVariable = 'some value'; // someVariable reassigned to 'some value'
someVariabble = 'another value'; // someVariable reassigend to 'another value'

variable declaration using var

Suppose a value is not provided at the time the variable is declared. In that case, the variable will be initialized with the value undefined. You can provide your user-defined value for initialization too:

var someVariable = 'some value'; // someVariable initialized to 'some value'

variable initialization to a string value using var

As stated earlier, these variables will be hoisted. While hoisting can be viewed as beneficial for function declarations, the hoisting of variables can lead to some "gotchas" if you're not careful.

Note: hoisting, as it is applied to functions, is what grants you the ability to declare functions either before or after you plan on calling them, which allows you more freedom in how you structure your code.

Not understanding how hoisting affects var declared variables can lead to what may seem to be strange side-effects. Still, the variables behave as intended. The most common mistake made, often perpetuated by those coming to JavaScript from other languages, is treating var declared variables as though they were block-scoped. The following snippet demonstrates this issue:

for (var counter = 0; counter < 10; counter += 1) {
// loop body
}

console.log(counter); // undefined variable or 10?

global scope variable hoisting at work - counter is accessible outside of the loop

As the comment indicates, one might believe that accessing the counter outside of the loop would result in an error, but that is not the case; the console will show the value 10. Using var to declare the variable will hoist it to the top of the global scope, and it will be available outside the loop. If you defined another variable named counter in the global scope, the declaration in the for loop would have no effect. You would be utilizing the same globally-scoped variable in the loop. This behaviour runs counterintuitive to what most developers have learned from other languages.

A variable can only be declared once using var, and redeclaring a variable with the same name in the same scope will have no effect. The result is that the variable identifier is hoisted, and the value is assigned (var does not perform initialization). The following snippet demonstrates what will happen if a variable is redeclared using var:

var num = 10; // num initialized to 10
var num; // this statement has no effect
console.log(); // 10

variables will only be declared once using var

Without var #

It is possible to declare a variable without providing a keyword. The caveat here is that the variable must also be initialized, or else it will result in a reference error.

someVariable; // reference error
someVariable = 'some value'; // someVariable initialized to 'some value'

variable initialization to a string value using var

Initializing variables in this way will help ensure that you don't access them before initialization. However, the variables will still exist only in the function or global scope they have been declared in (the same effect as having been declared with var). Initializing variables in this way is frowned upon, don't do it!

let #

Variables declared with let behave similarly to those declared with var; but there are some significant differences. For example, variables declared with let:

let someVariable; // someVariable initialized to undefined
let someVariable; // error, you cannot redeclare a variable using let

variable declaration using let - cannot be redeclared

Variables declared with let are still hoisted in the same way as var variables, but that hoisting now includes defined blocks. The following is the same loop example from above, only with the counter initialized using let. Notice that now we cannot access the counter outside of the loop body.

for (let counter = 0; counter < 10; counter += 1) {
// loop body
}

console.log(counter); // error, counter is not defined

block scope at work - counter is not accessible outside of the loop

So variables can be block-scoped, but they are still hoisted. What's most important when declaring and accessing variables is not the order in which the variable references appear but rather the order of execution and access to the variable. We have a function that accesses the externally declared variable num below to demonstrate that hoisting is still taking place. Though the function is declared and references num before its initialization, no error is raised because the function does not execute until after the variable initialization.

function fn() {
console.log(num); // num is referenced in code before initializaion
}

let num = 10;

fn(); // 10

variable is accessed after initialization

const #

Finally, we have const. Variables declared with const abide by all the same rules as variables declared with let, except that they must be initialized and cannot be reassigned. To be clear, while it may seem as though variables declared by const are immutable, that is not the case. It is simply impossible to reassign new value to a variable declared by const. So, if you initialize a const variable with a string, that variable will only ever return its initial value. Likewise, suppose you initialize a const variable with an object. In that case, you may still mutate the object, but you won't be able to reassign a new object to the variable.

const NUM; // error, missing initialization
const NUM = 10; // initialized to 10
NUM = 100; // error, invalid assignment

const variables must be initialized and cannot be reassigned

const obj = { foo: 'foo' }; // initialized to object
obj = {}; // error, invalid assignment
obj.bar = 'bar'; // valid object mutation
console.log(obj); // { foo: 'foo', bar: 'bar' }

const variables cannot be reassigned, but the values they reference are not immutable

Summary #

Given the various ways to declare variables, you may be wondering, "Which method should I use?" While there is no right or wrong answer to this question, I think we can prefer certain methods over others. First, we can make the case to avoid using var when declaring variables. Both let and const supersede var as each of the former keywords provides intuitive scoping behaviour and won't pollute the global namespace in the same cases as var. When it comes to choosing between let and const, likely many, or even most, variables you declare will never have to be reassigned. Therefore, declaring variables using const would be the best choice to prevent you from performing a reassignment in error. Only declare variables you will use for repeated assignments with let. Of course, the previous statements are merely suggestions. Take a look at whatever JavaScript style guide you're adhering to for direction on variable declaration and naming conventions.

The TLDR for variable declaration is simple: prefer const over let, and prefer let over var.

References #

Top