Javascript Temporal Dead Zone

  • Last updated on 11th Dec 2022

In this post, I will discuss the importance of the Principle of Least Exposure (POLE) in JS environments. Cybersecurity also has a related concept known as the Principle of Least Privilege (POLP). This principle involves a loosely-coupled system where each component has the minimum capabilities necessary to operate. This approach reduces the likelihood of the whole system being sabotaged in the event of an outage or compromise. Successful buildings have structural integrity and built-in redundancy to prevent complete failure if one component malfunctions, eliminating the possibility of the entire architectural blueprint being in shambles after a natural disaster.

Introduction:

The focus of POLE is at a lower level than POLP, which is more related to component-level design. For example, a loosely-coupled system design for React components would fall under POLP. As the global scope is the most accessible scope, let’s explore the idea of making all our variables widely available through the scope chain by placing them at the top using lexical scope.

Areas of Conflict

  • Naming Collisions: When a variable or function with a common and predefined name is used in two different parts of a program but is derived from one shared scope, it creates a collision, which often leads to errors. Sometimes, if the variable is not used as intended, it can cause bugs.

  • Unintentional Dependency: Refactoring problems could arise because other developers may be using and depending on private variables/functions that were unnecessarily exposed. This is one aspect of technical debt.

  • Unexpected Behavior: Exposure of private variables/functions can lead to unintended programmatic bugs. For example, if access to a list of objects inside an object array is granted, and that array is modified to include objects of different types, the program or a specific component may break.

The different types of scope

Function Scope

cache = {}

function factorial(n) {
  if (n === 0) {
    return 1
  }

  if (n in cache) {
    return cache[n]
  }

  cache[n] = n * factorial(n - 1)
  return cache[n]
}

console.log(factorial(5))
// 120

console.log(cache)
// { '1': 1, '2': 2, '3': 6, '4': 24, '5': 120 }

In the above example, the cache variable is declared outside of the function scope. This means that the cache variable is accessible to the entire program. This is a problem because the cache variable is not intended to be used outside of the factorial function. It is only intended to be used inside the factorial function. This is a violation of the POLE principle. We can improve this by wrapping our function in an IIFE and taking advantage of having access to function level scope via a function expression.

var factorial = (function () {
  cache = {}

  return function factorial(n) {
    if (n === 0) {
      return 1
    }

    if (n in cache) {
      return cache[n]
    }

    cache[n] = n * factorial(n - 1)
    return cache[n]
  }
})()

console.log(factorial(5))
// 120

console.log(cache)
// { '1': 1, '2': 2, '3': 6, '4': 24, '5': 120 }

Above, we used a named IIFE to create a function expression that returns a function. This is a common pattern. The cache variable is now only accessible inside the factorial function.

Function Boundaries: As a caution, with the inclusion of this, break, or continue within a function wrapped around a standalone IIFE, will not work inside because of boundaries. The IIFE will not be able to access an block or an outer loop.

Block scope

Block scope is formed when a variable is declared with let or const. Otherwise, it is only considered a statement. This is a new feature in ES6. Below is an example:

{
  // because a let or const has (yet) to appear, then its not a block scope

  // ..

  // NOW, its triggered to be a block scope

  let thisIsNowAScope = true

  for (let i = 0; i < 5; i++) {
    // The for loop here is a block scope, activated each iteration
    if (i % 2 == 0) {
      // the if statement here is only a block (also called a block statement)
      console.log(i)
    }
  }
}

// 0 2 4

Notes on eligibility of scope

Some pair of curly braces could be scopes, others not. Key-value pairs inside object literals not scope. They just produce a block statement. Javascript class declarations, although they use are not scopes either. They are just block statements. Functions and their are considered function scope. Switch statement’s case denotations do not have scope.

Ending Thoughts

In this article, we learned about how we can better code to account for security using POLE in our javascript. Discussing block-scope and function scope to better architect our code. Until then, have a good one!

Resources

Dasha Blog Scope

MDN Scope