Left ArrowBack

notes / JavaScript / scopes

scopes

JavaScript Scopes

Planted

Status: seed

POLP (The Principle of Least Privilege) states components of a system should be designed to function with least privilege, access & exposure. This makes the overall system stronger from a security standpoint. A compromise or failure of 1 piece has a minimized impact on the rest of the system. Other benefits include avoiding naming collisions, unexpected behaviour & unintended dependencies. For each piece, default to exposing the minimum. Keep everything else private. A scope enables control of a declaration's exposure.

A vintage elevator dial.

Levels

In JavaScript, scopes are determined at compile time. This is known as lexical scope. Each scope can only access declaration within itself or in parent scopes. However, during compliation, declarations may move to a different scope. There are 4 levels of scope:

/index.js

function diff(x,y) {
    if (x > y) {
        let tmp = x;
        x = y;
        y = tmp;
    }

    return y - x;
}

const x = 2;
const y = 4;

diff(x, y);

If a .js file is being imported into a .html file, its outer most scope is the global scope. Although the function arguments are highlighted, they aren't included in the global scope. Details below.

A function definition & call.

Arguments

Function & block scopes are between the {} brackets. This means a function's arguments aren't within a function's scope. They aren't in a function's parent scope either. When compiled, the location of arguments can be thought of as being in a new scope that wraps the function.

Before Compile

/index.js

function myFunc(input) {
   return input
}

myFunc(1)

After Compile

/index.js

{
   var input = 1

   function myFunc() {
      return input
   }
}

myFunc(1)

Before Compile

/index.js

const myArray = [...]

for (let i = 0; i < myArray.length; i++) {
   ...
}

...

After Compile

/index.js

const myArray = [...]

{
   let i = 0

   for (; i < myArray.length; i++) {
      ...
   }
}

...

This is why const can't be used in a for loop. It needs to be re-assigned after the 1st iteration via i++.

The words 'access granted'.

Accessing Variables & Functions

When a reference cannot be found within a scope, the parent scope is searched. If it still can't be found, the next parent scope is searched. This continues until the reference is found or there are no more scopes to search. At that point, a reference error will be thrown. Below is an example of a variable that is declared in the global scope but accessed from a function scope. The engine 1st searches the function scope for myVar. It can't find it, so it then searches the parent scope & finds the declaration.

/index.js

Console

const myVar = 1

function myFunc() {
   console.log(myVar)
}

myFunc()

Global Scope

The global scope is where:

  • JavaScript exposes:
    • primitives
    • natives
    • global functions: eval(), parseInt(), ...
    • namespaces: Math, JSON
    • Intl, WebAssembly
  • The environment hosting the JS engine exposes its own built-ins:
    • console
    • the DOM (window, document, ...)
    • timers (setTimeout(..), etc)
    • web platform APIs: navigator, history, geolocation, WebRTC, etc.

If the environment is the browser. A var or function declaration in the global scope will be added to the global object. This object is commonly accessed through window. However, it is better to use the standardized reference globalThis instead.

/index.js

Console

var myVar = 1;

console.log(globalThis.myVar);

IIFE

An application could include many global variables & functions from different source files. Limiting the number of these prevents problems like name collisions. 1 way to do this is to use an IIFE (Immediately Invoked Function Expression). Commonly used for initiating code (code that runs as soon as the JavaScript loads), it is a function that:

  • is invoked as soon as it is defined,
  • doesn't pollute the global namespace &
  • can't be invoked again.

index.js

(function () {
   // ...
})();

Where to Next?

A sci-fi robot taxi driver with no lower body