Brad Woods Digital Garden

Notes / JavaScript / Scopes

The Warhammer 40k Adeptus Mechanicus symbol

Table of contents

    A square with the letters 'JS' and the word 'scopes' next to it

    JavaScript Scopes

    Planted: 

    Status: decay

    Hits: 54

    POLP (The Principle of Least Privilege) states components of a system should be designed to function with least privilege, access and 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 and 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 and call.

    Arguments

    Function and 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 and 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 and finds the declaration.

    index.js

    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

    var myVar = 1;
    console.log(globalThis.myVar);

    IIFE

    An application could include many global variables and 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 and
    • can't be invoked again.

    index.js

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

    Feedback

    Have any feedback about this note or just want to comment on the state of the economy?

    Where to next?

    JavaScript
    Arrow pointing downYOU ARE HERE
    A Johnny Cab pilot