Getting Started with Modern JavaScript — Variables and Scope

In this article, we introduce variables and scope in JavaScript.

Variables

A variable is a named container with a unique name for storing data values. The statement below declares a variable with the name “car”:

let car;

console.log(car); // undefined

In JavaScript, variables are initialized with the value of undefined when they are created. You can assign a value to a variable using the assignment operator (=) when you declare it:

let car = 'Volvo';

console.log(car); // Volvo

Always initialize your variables before using them or you will get an error:

console.log(car); // ReferenceError: car is not defined

const car = "Toyota";

ECMAScript 2015 (or ES6) introduced two new ways of declaring variables, let and const. The reason for the new keywords was because the function scoping of var is confusing. It was one of the main sources of bugs in JavaScript.

Scope

By scope, we are talking about the visibility of variables in the different parts of the code during runtime. Or in other words which parts of the code can access and modify a variable.

In JavaScript there are two types of scope:

  • Global scope
  • Local scope

What changed with Modern JavaScript (ES6+) is the way we use variables in the local scope.

js-scopes.png

Global Scope

A variable declared outside a function becomes global. This means it can be accessed and modified everywhere in the code.

We can declare constants in the global scope:

const COLS = 10;
const ROWS = 20;</span>

We can then access them from all parts of our code.

Local Scope

Variables declared in a local scope can not be accessed from outside that scope. The same variable name can be used in different scopes because they are bound to their respective scopes.

Local scope differs depending on the variable declaration used.

Function Scope

Variables declared with the var keyword become local to the function. They can be accessed from within the function.

function printCar() {
  if(true) {
    console.log(car); // undefined
    var car = "Porsche";
    console.log(car); // "Porsche" 
  }
  console.log(car); // "Porsche"
}

printCar();
console.log(car); // ReferenceError

We can see that we don’t get an error even though we access car before the declaration. Variables declared with the var keyword are hoisted — moved to the top of the function and initialized with undefined before the code is run. With the hoisting, they are accessible in their enclosing scope even before they are declared.

Can you see how this can get confusing?

Block Scope

The concept of block scope was introduced in ES6 together with the new ways to declare variables — const and let. This means that the variable is accessible between two curly braces {}. For example inside an if or for.

function printCar() {
  if(true) {
    console.log(car); // ReferenceError
    const car = "Fiat";
    console.log(car); // "Fiat" 
  }
  console.log(car) // ReferenceError
}

printCar();
console.log(car); // ReferenceError

The let and const variables are not initialized until their definition is evaluated. They are not hoisted as in the function scoping. Accessing them before the initialization results in a ReferenceError.

I hope you can see how this is easier to reason about.

Const vs Let

So now that we know that we should use let and const, when should we use which?

The difference between the two is that the value of a const can’t be changed through reassignment, and it can’t be re-declared. So if we don’t need to reassign we should use const. This also makes the code clearer since we have one variable to represent one thing.

You could even always declare the variables as const until you see that you need to reassign the variables and then change to let. One example of when you need let is in loops:

for(let i = 0; 0 < 10; i++) {
  console.log(i); // 1, 2, 3, 4 …
}

Conclusion

  • Variables declared on the global scope are accessible everywhere in your code.
  • Variables declared in a local scope can not be accessed from outside that scope.
  • const and let use block scope which exists between two curly braces.
  • Mostly use const for variables whose values will never change.
  • For everything else use let.
  • Don’t use var to avoid confusion.

No Comments Yet