This page looks best with JavaScript enabled

Variable Scoping in Javascript

 ·   ·  ☕ 5 min read

Scope of a variable refers to the visibility of that variable. Since the visibility of a variable also determines whether it can be referenced in a valid way, scopes are said to define the ‘life time of a variable’. Scopes in Javascript can be global to the program, or local to the specific block and function.

Before going further, a couple of lines on the basics

Javascript is an interpreted language, but runs code using a compiler + interpreter engine combo. So, this is the normal execution of the program -

  • Compile

    Compile code. Move declarations at the very top of scope and remember those declarations (this is also called ‘hoisting’). Even if the variable is initialized during declaration, the compiler does not assign values at this time.

  • When execution engine encounters variable assignment, it allocates memory and points variable to the memory location

With this in mind, let us rock and roll.

Global scope

Any variable declared within a program but outside of a function is said to be global. Such variables can be accessed from anywhere within the program.

1
2
3
4
5
6
7
8
let x = 1;
console.log("x global: ", x); // x global:  1

display();

function display() {
  console.log("x function: ", x); // x function:  1
}

Local scope

Any variable declared locally in a function will be accessible only within that function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let x = 1;
console.log("x global: ", x); // x global:  1

console.log("y function local: ", y);
// program errors out since there is no variable called 'y'

display();

function display() {
  let y = 3;
  console.log("x function: ", x); // x function:  1
  console.log("y function local: ", y); // x function:  1
}

The same is true for a block.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
let x = 1;
console.log("x global: ", x); // x global:  1

// console.log("y function local: ", y);
// program errors out since there is no variable called 'y'

display();

function display() {
  let y = 3;
  console.log("x function: ", x); // x function:  1
  console.log("y function local: ", y); // y function:  3

  //console.log("z block local: ", z);
  //program errors out since there is no variable called 'z'

  if (y == 3) {
    let z = 5;
    console.log("y function local: ", y); // x function:  3
    console.log("z block local: ", z); // x function:  5
  }
}

You now see the pattern - while function or block has access to parent variables, child variables are not available to the parent.

You would also have noticed that I used let. This will tie the variable to the parent block / function scope.

If I had used var instead, we have slightly different result.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
//console.log("y global: ", y); // y global:  3
//program errors out since there is no variable called 'z'

display();

function display() {
  var y = 3;
  console.log("y function local: ", y); // y function:  3
  console.log("z function local 1: ", z); // z function:  undefined, no error - DIFFERING BEHAVIOUR

  if (y == 3) {
    var z = 5;
    console.log("y function local: ", y); // x function:  3
    console.log("z block local: ", z); // x function:  5
  }
  console.log("z function local 2: ", z); // z function:  5 - DIFFERING BEHAVIOUR
  // If we had used let z = 5 in declaration, this line would have failed.
}

The above variable visibility behaviour should be the single biggest reason for you to switch from var to let. The program throws an error for a variable that is not accessible rather than having a silent ‘undefined’, or showing the value that was supposed to be within a block.

The above example with var also illustrates the definition of a ‘lexical scope’. Variable value gets defined by the position of the variable rather than the block.

Behaviour of let

  • let moved variable declaration to beginning of the block at compile time
  • Execution engine could not find any definition of z at z function local 1 and errored out
  • Same is the case if variable is found after the parent block in which it is defined

Behaviour of var

  • var moved variable declaraion to beginning of everything at compile time
  • Execution engine could see the definition of z at z function local 1, but not find any value. Returned undefined and continued
  • Execution engine went through the block in which z value was assigned
  • Engine encounters z again at z function local 2 and prints the value assigned within the block

const has the same behaviour as let.

Module scope

An variable declared within the module stays within the module. If the Javascript execution context is executing multiple modules across the board, variables are not accessible across the board.

To make variables in one module available to others, you have to explicitly export the variable.

1
2
// within the module file sum.js
export { x, y };

These variables can then be used in other modules using an import statement.

1
2
3
4
// within the module file math-op.js
import { x, y } from "./sum.js";

// ... rest of the module

Takeaways

  • Define variables only when necessary. Make them local to a block / function and avoid global variables
  • Use let / const instead of var
Stay in touch!
Share on

Prashanth Krishnamurthy
WRITTEN BY
Prashanth Krishnamurthy
Technologist | Creator of Things