This note serves as a reminder of the book's content, including additional research on the mentioned topics. It is not a substitute for the book. Most images are sourced from the book or referenced.
All notes in this series
Infor & Preface
Attention: decisions and patterns we apply across the whole program.
- 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?
- Naming Collisions: Identical names for variables or functions can lead to collisions, resulting in bugs.
- Unexpected Behavior: If access is granted to parts that are supposed to be private, other individuals may perform actions you did not intend.
- 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
orconst
, don’t usevar
!
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}
- Use
let
orconst
to block the scope to lowest level but how to hidevar
orfunction
too?
- Hide
var
by wrapping it by afunction
.
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.