👉 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).
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
letorconst, 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
letorconstto block the scope to lowest level but how to hidevarorfunctiontoo?
- Hide
varby 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); // 7201// 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); // 720Hide
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.