Reading: You Don't Know JS Yet 2 (Scope & Closures) - Quick notes (from Chapter 6)

Anh-Thi Dinh
👉 List of all notes for this book. IMPORTANT UPDATE Nov 18, 2024: I've stopped taking detailed notes from the book and now only highlight and annotate directly in the PDF files/book. With so many books to read, I don't have time to type everything. In the future, if I make notes while reading a book, they'll contain only the most notable points (for me).

Chap 6 — Limiting Scope Exposure

Attention: decisions and patterns we apply across the whole program.

Least Exposure

  • How and why we use different levels of scopes (functions and blocks)? ← functions create their own scope, it’s normal but why we need blocks?
  • In Software Engineering, we have The Principle of Least Privilege (POLP - a concept in computer security that limits users' access rights to only what is strictly required to do their jobs) → its variation in this section is “Least Exposure” (POLE).
  • Following POLE, we want to minimize the exposure of variables in each scope.
  • [Bad idea] Placing all variables in the global scope, why?
      1. Naming Collisions: Identical names for variables or functions can lead to collisions, resulting in bugs.
      1. Unexpected Behavior: If access is granted to parts that are supposed to be private, other individuals may perform actions you did not intend.
      1. Unintended Dependency: If developers outside of your program create a dependency on some "supposed to be private" parts of your program, future changes to these parts could unexpectedly affect these external dependencies.
→ Exposing min necessary, keeping everying else as private as possible.
  • In order to block the variable to the block scope, use let or const, don’t use var!
    • 1function diff(x, y) {
      2  console.log(tmp); // ReferenceError with "const" and "let", undefined with "var"
      3  if (x > y) {
      4    const tmp = x; // or let or var
      5    x = y;
      6    y = tmp;
      7  }
      8  return y - x;
      9}

Hiding in Plain (Function) Scope

  • Use let or const to block the scope to lowest level but how to hide var or function too?
  • Hide var by wrapping it by a function.
    • 1var cache = {} // will be in the global scope
      2function factorial(x) {
      3	if (x < 2) return 1; if (!(x in cache)) {
      4		cache[x] = x * factorial(x - 1);
      5	}
      6	return cache[x];
      7}
      8factorial(6); // 720
      1// outer scope
      2function hideTheCache() {
      3	// middle scope
      4	var cache = {}
      5	function factorial(x) {
      6		if (x < 2) return 1; if (!(x in cache)) {
      7			cache[x] = x * factorial(x - 1);
      8		}
      9		return cache[x];
      10	}
      11}
      12var factorial = hideTheCache();
      13factorial(6); // 720
      Hide cache. ← Weakness: different hideTheCache for different variables like cache → collisions!
      1var factorial = (function hideTheCache() {
      2	var cache = {}
      3	function factorial(x) {
      4		if (x < 2) return 1; if (!(x in cache)) {
      5			cache[x] = x * factorial(x - 1);
      6		}
      7		return cache[x];
      8	}
      9})() // () means "immediate invoke the function"
      Don’t affraid of the collisions. We can use again hideTheCache in other places because it isn’t in the outer scope. Read again section “Function Name Scope”.
❇️ Invoking Function Expressions Immediately
The last () in the previous code is call Immediately Invoked Function Expression (IIFE). It’s useful to create a scropt to hide var/func.
1// standalone IIFE -> "()" surround function is required
2(function(){ .. })();
3
4// with a name -> "()" surround function isn't required
5(function namedIIFE(){ .. })();
6function nameIIFE(){...}()
IIFE.