From a6e17b761b38773ca88dd3bbb423010ce5a2ddbd Mon Sep 17 00:00:00 2001 From: HariHaran Date: Thu, 14 Oct 2021 14:11:02 +0530 Subject: [PATCH 1/7] Hacktoberfest --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d9c7998..fe637b7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@ # JavaScript-A-Z-Notes -This is everything you need to know about the lanuguage of the future, Javascript! + +

+ +![JavaScript-A-Z-Notes](https://socialify.git.ci/HariAcidReign/JavaScript-A-Z-Notes/image?description=1&font=Raleway&forks=1&logo=https%3A%2F%2Fwww.workinggears.com%2Fimages%2Fservices%2Fjs-ts.jpg&owner=1&stargazers=1&theme=Dark) + +

+ +

This is everything you need to know about the lanuguage of the future, Javascript! Open for Hacktoberfest ✨

## 🎯 Purpose This is my attempt at sharing JS knowledge with everyone, even those who might not have the time to go through all the videos. Also, I will use this repo for quick reference to JS concepts when necessary. I made the mistake of writing notes on pen and paper while doing the Machine Learning course by AndrewNG and now its collecting 🕸️. Figured this would be a better way of documenting my journey 🔥 From 08f209053ec38ee18dbb2551862aab63ed845c5c Mon Sep 17 00:00:00 2001 From: Jatin Oza Date: Fri, 15 Oct 2021 03:58:07 +0530 Subject: [PATCH 2/7] text updated --- Notes/10-Closures.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Notes/10-Closures.md b/Notes/10-Closures.md index ea27aab..b91ed3c 100644 --- a/Notes/10-Closures.md +++ b/Notes/10-Closures.md @@ -22,6 +22,7 @@ console.log(z); // value of z is entire code of function y. When functions are returned from another fun, they still maintain their lexical scope. - When y is returned, not only is the fun returned but the entire closure (fun y + its lexical scope) is returned and put inside z. So when z is used somewhere else in program, it still remembers var a inside x() +- Closure is a very powerful concept of JS, just because this function remembers things even if they are not in their lexical scope ### Uses of Closure Module Design Pattern, Currying, Functions like once(fun that can be run only once), memoize, maintaining state in async world, setTimeout, iterators... From e0231f8fb3ae8958f66c2c16a7eb2a53b1858a1d Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 14 Oct 2021 22:31:30 +0000 Subject: [PATCH 3/7] Restyled by prettier-markdown --- Notes/10-Closures.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Notes/10-Closures.md b/Notes/10-Closures.md index b91ed3c..753363d 100644 --- a/Notes/10-Closures.md +++ b/Notes/10-Closures.md @@ -1,7 +1,8 @@ # Episode 10 : Closures in JS + ### Important Interview Question -**Closure :** Function bundled together with its lexical environment/scope. +**Closure :** Function bundled together with its lexical environment/scope. ``` JS is a weird language. You can pass functions as parameters to another function, assign a variable to an entire function, or even return a function. @@ -19,10 +20,16 @@ console.log(z); // value of z is entire code of function y. ``` -When functions are returned from another fun, they still maintain their lexical scope. -- When y is returned, not only is the fun returned but the entire closure (fun y + its lexical scope) is returned and put inside z. So when z is used -somewhere else in program, it still remembers var a inside x() -- Closure is a very powerful concept of JS, just because this function remembers things even if they are not in their lexical scope +When functions are returned from another fun, they still maintain their lexical +scope. + +- When y is returned, not only is the fun returned but the entire closure (fun + y + its lexical scope) is returned and put inside z. So when z is used + somewhere else in program, it still remembers var a inside x() +- Closure is a very powerful concept of JS, just because this function remembers + things even if they are not in their lexical scope ### Uses of Closure -Module Design Pattern, Currying, Functions like once(fun that can be run only once), memoize, maintaining state in async world, setTimeout, iterators... + +Module Design Pattern, Currying, Functions like once(fun that can be run only +once), memoize, maintaining state in async world, setTimeout, iterators... From 1203808af9f73da6ecef93835c6e896f706d2288 Mon Sep 17 00:00:00 2001 From: suman-saket <54411834+suman-saket@users.noreply.github.com> Date: Thu, 24 Mar 2022 15:12:08 +0530 Subject: [PATCH 4/7] Update README.md It was written in Code Example 5undefined but it should be ReferenceError: x is not defined. --- Notes/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Notes/README.md b/Notes/README.md index 756fc31..4d0921f 100644 --- a/Notes/README.md +++ b/Notes/README.md @@ -160,7 +160,7 @@ function getName(){ Output: > Namaste JavaScript -> undefined +> ReferenceError: x is not defined > f getName(){ console.log("Namaste JavaScript); From 0e3c33cb1c887a84f79aab7169661e802bbf86b0 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 24 Mar 2022 09:42:44 +0000 Subject: [PATCH 5/7] Restyled by prettier-markdown --- Notes/README.md | 729 +++++++++++++++++++++++++----------------------- 1 file changed, 386 insertions(+), 343 deletions(-) diff --git a/Notes/README.md b/Notes/README.md index 4d0921f..942534b 100644 --- a/Notes/README.md +++ b/Notes/README.md @@ -2,20 +2,22 @@ # Episode 1 : Execution Context -### Everything in JS happens inside the execution context. +### Everything in JS happens inside the execution context. Assume execution context to be a big box where everything takes place. It has 2 components in it: +
  • Memory : The place where all the variables and functions are stored as (key:value) pairs. Memory component is also known as variable environment.
  • Code : The place where code is executed one line at a time. Code component is also known as Thread of Execution -### JS is a synchronous single-threaded language. +### JS is a synchronous single-threaded language. +
  • By single threaded, we mean JS can only run 1 command at a time
  • By synchronous single threaded, we mean it can run 1 command at a time, in a specific order # Episode 2 : Execution & Call Stack Everytime you run a program, an execution context is created. -When a variable or function is encountered, it is stored in the memory area. +When a variable or function is encountered, it is stored in the memory area. ``` var n=2; @@ -28,35 +30,39 @@ var square2 = square(n); var square4 = square(4); ``` + Now first, for this entire code a Global execution context is created. ### In the first phase (memory creation) + - Memory is allocated to variables and functions. - For variable name(which is key) it assigns a value of undefined - For the function name(which is key) it assigns the entire function code as value. ``` -n:undefined +n:undefined square:{...entire-code...} -square2:undefined +square2:undefined square4:undefined ``` ### In the second phase (code execution) -- The variable name is replaced with its actual assigned value from code. So now n:2 -- Skips over function code as there is nothing to assign there. -- We encounter a function call in square2. So a brand new local EC is created inside the code part of global EC and this will have the same 2 components: Memory and Code. -- In the local EC, ans and num are both undefined (in first phase). Then, the n value in global EC is passed to num, replacing undefined. num is the parameter and n is the argument. -- ans = num*num (calculated in code part of local EC and returned) replaces undefined in local EC (memory part) and the final value is returned from local and is assigned to square2 var in global. + +- The variable name is replaced with its actual assigned value from code. So now n:2 +- Skips over function code as there is nothing to assign there. +- We encounter a function call in square2. So a brand new local EC is created inside the code part of global EC and this will have the same 2 components: Memory and Code. +- In the local EC, ans and num are both undefined (in first phase). Then, the n value in global EC is passed to num, replacing undefined. num is the parameter and n is the argument. +- ans = num\*num (calculated in code part of local EC and returned) replaces undefined in local EC (memory part) and the final value is returned from local and is assigned to square2 var in global. After returning, local EC is removed form global EC and control goes back to global. -- One more fun. call is met. Same thing happens here. -Once square4 value is replaced from undefined to 16, global EC will also be deleted. +- One more fun. call is met. Same thing happens here. + Once square4 value is replaced from undefined to 16, global EC will also be deleted. To manage all these EC, a call **stack** is created. Everytime code is run, the EC is pushed in. So first global EC is pushed. Then e1 EC(for square2) is pushed, and then after -value returned, is popped. Similarly e2 EC(for square4) is pushed, and then popped and finally Global is also popped and stack is empty. +value returned, is popped. Similarly e2 EC(for square4) is pushed, and then popped and finally Global is also popped and stack is empty. > Call Stack maintains the order of execution of execution contexts + #### Call stack aka Execution control stack, program stack, control stack, runtime stack ad machine stack # Episode 3 : Hoisting @@ -77,15 +83,15 @@ console.log(x); Output: -> Namaste JavaScript +> Namaste JavaScript -> 7 +> 7 ``` // code example 2 -getName(); // in most languages, both lines which are above their declaration will give error. Not in JS though. -console.log(x); +getName(); // in most languages, both lines which are above their declaration will give error. Not in JS though. +console.log(x); var x = 7; @@ -95,10 +101,11 @@ function getName(){ ``` - Output: -> Namaste JavaScript +Output: -> undefined +> Namaste JavaScript + +> undefined ``` // code example 3 @@ -114,14 +121,14 @@ function getName(){ Output: -> Namaste JavaScript +> Namaste JavaScript -> Error: x is not defined // note that not defined here and "undefined" in sample 2 are totally different. +> Error: x is not defined // note that not defined here and "undefined" in sample 2 are totally different. -- Not defined: We have not initialised the value for variable anywhere in the entire code and in memory space. -- Undefined: +- Not defined: We have not initialised the value for variable anywhere in the entire code and in memory space. +- Undefined: -__Hoisting__ is a concept which enables us to extract values of variables and functions even before initialising/assigning value without getting *error* +**Hoisting** is a concept which enables us to extract values of variables and functions even before initialising/assigning value without getting _error_ ``` @@ -139,9 +146,10 @@ console.log(getName) Output: > f getName(){ + console.log("Namaste JavaScript); - } +} ``` @@ -158,13 +166,16 @@ function getName(){ ``` Output: -> Namaste JavaScript -> ReferenceError: x is not defined +> Namaste JavaScript + +> ReferenceError: x is not defined + +> f getName(){ -> f getName(){ console.log("Namaste JavaScript); - } + +} ``` // code example 6 @@ -175,7 +186,7 @@ var getName = function () { console.log("Namaste JavaScript"); } -var getName = () => { // use fat arrow function +var getName = () => { // use fat arrow function console.log("Namaste JavaScript"); } @@ -183,15 +194,15 @@ var getName = () => { // use fat arrow function Output: -> undefined //it is because they behave as variable and not function. +> undefined //it is because they behave as variable and not function. --- -__REASON OF WEIRDNESS__ +**REASON OF WEIRDNESS** -* The answer lies in the Global Exection Context. In the memory phase, the variables will be initialized as *undefined* and functions will get the whole function code in their memory. +- The answer lies in the Global Exection Context. In the memory phase, the variables will be initialized as _undefined_ and functions will get the whole function code in their memory. -* This is the reason why we are getting these outputs. +- This is the reason why we are getting these outputs. # Episode 4 : Functions and Variable Environments @@ -225,15 +236,15 @@ Outputs: ### Code Flow - The Global Execution Context (GEC) is created (the big box with Memory and Code subparts). Also GEC is pushed into Call Stack -> Call Stack : GEC + > Call Stack : GEC - In first phase of GEC (memory phase), variable x:undefined and a and b have their entire function code as value initialized - In second phase of GEC (execution phase), when the fun is called, a new local EC is made. After x = 1 assigned to GEC x, a() is called. So local EC for a is made inside code part of GEC. -> Call Stack: [GEC,a()] + > Call Stack: [GEC,a()] - For local EC, a totally different x variable assigned undefined(x inside a()) in phase 1 , and in phase 2 it is assigned 10 and printed in console log. After printing, no more -commands to run, so a() local EC is removed from both GEC and from Call stack -> Call Stack: GEC + commands to run, so a() local EC is removed from both GEC and from Call stack + > Call Stack: GEC - Cursor goes back to b() function call. Same steps repeat. -> Call Stack :[GEC, b()] -> GEC (after printing yet another totally different x value as 100 in console log) + > Call Stack :[GEC, b()] -> GEC (after printing yet another totally different x value as 100 in console log) - Finally GEC is deleted and also removed from call stack. Program ends. # Episode 5: Window and this keyword @@ -242,10 +253,11 @@ commands to run, so a() local EC is removed from both GEC and from Call stack - Shortest JS program is nothing but an Empty JS file - Even for this program, JS engine does a lot behind the scenes -- It creates the GEC, the "window" and the *this* variable +- It creates the GEC, the "window" and the _this_ variable - Window is a big global object that has a lot of functions and variables. All of these can be accessed from anywhere in the program -- *this* points to *window* -> this === window -> true (at global level) +- _this_ points to _window_ + > this === window -> true (at global level) + ``` var a = 10; // not inside any fun. So global object function b() { // this fun not inside any function. So global. @@ -254,18 +266,19 @@ function b() { // this fun not inside any function. So global. console.log(window.a); //gives us "a" value console.log(this.a); //this points to window so it returns "a" value console.log(a); //also gives same "a" value. (if we dont put any . in front of variable, it **assumes variable is in global space** -console.log(x); // x is not defined. (tries to find x inside global space, but it isn't there) +console.log(x); // x is not defined. (tries to find x inside global space, but it isn't there) ``` + - Global space is anything in JS which isn't inside a function. All these global objects will be present inside the windows schema. But non globals ones won't be there (here, x) -- When a GEC is made, *this* is also created with it (even for functional(local) EC). Global object provided by the browser engine is the window, so *this* points to window. +- When a GEC is made, _this_ is also created with it (even for functional(local) EC). Global object provided by the browser engine is the window, so _this_ points to window. # Episode 6: Undefined vs Not Defined -- In first phase (mem alloc) JS assigns each variable to a placeholder called *undefined* -- *undefined* is when memory is allocated for the variable, but no value is assigned yet. -- If an object/variable is not even declared/found in mem alloc phase, and tried to access it then it is *Not defined* +- In first phase (mem alloc) JS assigns each variable to a placeholder called _undefined_ +- _undefined_ is when memory is allocated for the variable, but no value is assigned yet. +- If an object/variable is not even declared/found in mem alloc phase, and tried to access it then it is _Not defined_ -> When variable is declared but not assigned value, its current value is undefined. But when the variable itself is not declared but called in code, then it is not defined. +> When variable is declared but not assigned value, its current value is undefined. But when the variable itself is not declared but called in code, then it is not defined. ``` console.log(x); @@ -275,14 +288,14 @@ console.log(x); console.log(a); ``` ->undefined
    ->25
    ->Uncaught ReferenceError: a is not defined +> undefined
    +> 25
    +> Uncaught ReferenceError: a is not defined - JS is a loosely-typed / weakly-typed language. It doesn't attach variables to any datatype. We can say var a = 5, and then change the value to bool (a = true) or string -(a = 'hello') later on. -- **Never** assign *undefined* to a variable manually. Let it happen on it's own accord. + (a = 'hello') later on. +- **Never** assign _undefined_ to a variable manually. Let it happen on it's own accord. # Episode 7 : Scope and Lexical Environment @@ -290,8 +303,8 @@ console.log(a); This is why JS is confusing (Case-1) function a() { - console.log(b); // surprisingly instead of printing undefined it prints 10. - //So somehow this b could access the b outside the fun. + console.log(b); // surprisingly instead of printing undefined it prints 10. + //So somehow this b could access the b outside the fun. } var b = 10; @@ -309,11 +322,11 @@ function a() { } var b = 10; a(); - + -------------------- - + Another one (DJ KHALED!) (Case-3) - + function a() { var b = 10; c(); @@ -321,7 +334,7 @@ function a() { console.log(b); //it prints the right value. How? See ans below Summary part } } - + a(); console.log(b); // now when cursor comes here, it prints NOT DEFINED! @@ -331,34 +344,36 @@ function a() { - Scope is directly dependent on the lexical environment - **Lexical Environment** : local memory + lexical env of its parent - Whenever an EC is created, a Lexical environment(LE) is also created and is referenced in the local EC(in memory space) -- Lexical means hierarchy. In the DJ KHALED (xD) code, function c is lexically inside function a. +- Lexical means hierarchy. In the DJ KHALED (xD) code, function c is lexically inside function a. - So in EC of c(), variables and fun in c (none) + reference of lexical env of parent a() is there - LE of a() in turn is its memory space + reference to LE of parent (Global EC) -- LE of Global EC points to *null* +- LE of Global EC points to _null_ + +``` + To summarize the above points: + + call_stack = [GEC, a(), c()] + + Now lets also assign the memory sections of each execution context in call_stack. - ``` - To summarize the above points: - - call_stack = [GEC, a(), c()] + c() = [[lexical environment pointer pointing to a()]] - Now lets also assign the memory sections of each execution context in call_stack. + a() = [b:10, c:{}, [lexical environment pointer pointing to GEC]] - c() = [[lexical environment pointer pointing to a()]] + GEC = [a:{},[lexical_environment pointer pointing to null]] - a() = [b:10, c:{}, [lexical environment pointer pointing to GEC]] +``` + +### For case -3 - GEC = [a:{},[lexical_environment pointer pointing to null]] +- First JS engine searches for b in local mem of c(). Nothing is there. +- So it goes to the reference of Lexical env of parent a(). Here b = 10 is here. So it takes this value, goes back to c() and console prints it. +- Had b not been in a(), then pointer would have gone to a()'s parent (Global EC and searched there). Had b not been there too, then it goes to LE of global's parent + which is null. Now JS engine stops and says b is NOT DEFINED. +- **Lexical env of c = Local memory of c + LE of A + LE of Global** +- This process of going one by one to parent and checking is called **scope chain** - ``` - ### For case -3 - - First JS engine searches for b in local mem of c(). Nothing is there. - - So it goes to the reference of Lexical env of parent a(). Here b = 10 is here. So it takes this value, goes back to c() and console prints it. - - Had b not been in a(), then pointer would have gone to a()'s parent (Global EC and searched there). Had b not been there too, then it goes to LE of global's parent - which is null. Now JS engine stops and says b is NOT DEFINED. - - **Lexical env of c = Local memory of c + LE of A + LE of Global** - - This process of going one by one to parent and checking is called **scope chain** - - # Episode 8 : let, const, temporal dead zone, types of errors +# Episode 8 : let, const, temporal dead zone, types of errors > let and const declarations are hoisted. But its different from var @@ -371,15 +386,16 @@ console.log(a); // 10 var b = 15; ``` + It looks like let isn't hoisted, **but it is** -- Both a and b are actually initialized as *undefined* in hoisting stage. But var b is inside the storage space of GLOBAL, and a is in a separate memory(script), where it can be -accessed only after assigning some value to it first. +- Both a and b are actually initialized as _undefined_ in hoisting stage. But var b is inside the storage space of GLOBAL, and a is in a separate memory(script), where it can be + accessed only after assigning some value to it first. - ie. one can access 'a' only if it is assigned. Thus, it throws error. -- **Temporal Dead Zone** : Time since when the let variable was hoisted until it is initialized some value. +- **Temporal Dead Zone** : Time since when the let variable was hoisted until it is initialized some value. - So any line till before "let a = 10" is the TDZ for a -- Since a is not accessible on global, its not accessible in *window/this* also -> window.b or this.b -> 15; But window.a or this.a ->undefined, just like window.x->undefined (x isn't declared anywhere) +- Since a is not accessible on global, its not accessible in _window/this_ also + > window.b or this.b -> 15; But window.a or this.a ->undefined, just like window.x->undefined (x isn't declared anywhere) ``` let a = 10; @@ -390,9 +406,10 @@ var a = 100; // this code also rejected upfront as SyntaxError. (can't use same name in same scope) ``` + Let is a stricter version of var. Now, **const** is even more stricter than let. --const holds all above properties of let. +-const holds all above properties of let. ``` let a; @@ -406,42 +423,45 @@ console.log(b); // SyntaxError: Missing initializer in const declaration. ------------------ const b = 100; b = 1000; -//this gives us TypeError: Assignment to constant variable. +//this gives us TypeError: Assignment to constant variable. ``` + - Till now 3 types of errors have been covered: Syntax, Reference, and Type. * Uncaught ReferenceError: x is not defined at ... - * This Error signifies that x has never been in the scope of the program. This literally means that x was never defined/declared and is being tried to be accesed. + - This Error signifies that x has never been in the scope of the program. This literally means that x was never defined/declared and is being tried to be accesed. * Uncaught ReferenceError: cannot access 'a' before initialization - * This Error signifies that 'a' cannot be accessed because it is declared as 'let' and since it is not assigned a value, it is its Temporal Dead Zone. Thus, this error occurs. + - This Error signifies that 'a' cannot be accessed because it is declared as 'let' and since it is not assigned a value, it is its Temporal Dead Zone. Thus, this error occurs. * Uncaught SyntaxError: Identifier 'a' has already been declared - * This Error signifies that we are redeclaring a variable that is 'let' declared. No execution will take place. - - ``` - //code example 1.1 - let a=10; - let a=100; - ``` - ``` - //code example 1.2 - let a=10; - var a=100; - ``` - - Will throw this Syntax error and no code will be run and be rejected affront. - 'let' is a strict form of declaration and thus can be done only once. + - This Error signifies that we are redeclaring a variable that is 'let' declared. No execution will take place. + + ``` + //code example 1.1 + let a=10; + let a=100; + ``` + + ``` + //code example 1.2 + let a=10; + var a=100; + ``` + + Will throw this Syntax error and no code will be run and be rejected affront. + 'let' is a strict form of declaration and thus can be done only once. + * Uncaught SyntaxError: Missing initializer in const declaration - * This Error signifies that we haven't initialized or assigned value to a const declaration. -* Uncaught TypeError: Assignment to constant variable - * This Error signifies that we are reassigning to a const variable. + - This Error signifies that we haven't initialized or assigned value to a const declaration. +* Uncaught TypeError: Assignment to constant variable + - This Error signifies that we are reassigning to a const variable. ### Type Error: @@ -449,7 +469,7 @@ The Errors that occur due to conflicts with the declaration type. For example re ### Syntax Error: -The Errors that occur due to wrong syntax that doesn't match with JS Engine syntactical rules. +The Errors that occur due to wrong syntax that doesn't match with JS Engine syntactical rules. For example, if const is not initialized, it will throw syntax error as by syntax, it must initialize if it sees a const declaration. @@ -459,20 +479,20 @@ Also, if variable that is assigned with 'let' declaration is tried to re-declare The Errors that occurs if no reference is available for access. Can occur when the variable is no where in scope or maybe it is in temporal dead zone. - ### SOME GOOD PRACTICES: -* Try using const wherever possible. -* If not, use let. -* Avoid var. -* Declare and initialize all variables with let to the top to avoid errors to shrink temporal dead zone window to zero. +- Try using const wherever possible. +- If not, use let. +- Avoid var. +- Declare and initialize all variables with let to the top to avoid errors to shrink temporal dead zone window to zero. PS: If in any interview when asked "Are let and const hoisted?" explain fully about temporal deadzone and all the above concepts too # Episode 9 : Block Scope and Shadowing ### What is a block? -- Block aka *compound statement* is used to group JS statements together into 1 group. We group them within {...} + +- Block aka _compound statement_ is used to group JS statements together into 1 group. We group them within {...} - The purpose is to group multiple statments at a place where JS expects only 1 statement. ``` @@ -493,12 +513,12 @@ if(true){ } ``` -* The {} block treats all the statements as one statement. -* The if doesnt have any curly braces in syntax. +- The {} block treats all the statements as one statement. +- The if doesnt have any curly braces in syntax. -### __BLOCK SCOPE__ +### **BLOCK SCOPE** -* What are the variables and functions that can be accessed inside the block. +- What are the variables and functions that can be accessed inside the block. ``` //code example 3 @@ -519,16 +539,16 @@ Outputs: > Uncaught ReferenceError: b is not defined -* Behind the Scenes: +- Behind the Scenes: - * In the BLOCK SCOPE; we get b and c inside it initialized as *undefined* as a part of hoisting (in a seperate memory space called block) - * While, a is stored inside a GLOBAL scope. + - In the BLOCK SCOPE; we get b and c inside it initialized as _undefined_ as a part of hoisting (in a seperate memory space called block) + - While, a is stored inside a GLOBAL scope. -* Thus we say, *let* and *const* are BLOCK SCOPED. They are stored in a separate mem space which is reserved for this block. Also, they can't be accessed outside this block. -But var a can be accessed anywhere as it is in global scope. -* Thus, we can't access them outside the Block. +- Thus we say, _let_ and _const_ are BLOCK SCOPED. They are stored in a separate mem space which is reserved for this block. Also, they can't be accessed outside this block. + But var a can be accessed anywhere as it is in global scope. +- Thus, we can't access them outside the Block. -### __What is SHADOWING in JS?__ +### **What is SHADOWING in JS?** ``` //code example 4 @@ -540,17 +560,18 @@ var a = 100; const c = 30; console.log(a); // 10 console.log(b); // 20 - console.log(c); // 30 + console.log(c); // 30 } -console.log(a); // 10 instead of the 100 we were expecting. So block "a" modified val of global "a" as well. -// In console, only b and c are in block space. a initially is in global space(a = 100), and when a = 10 line is run, a is not created in block space, but replaces 100 with 10 in global space itself. +console.log(a); // 10 instead of the 100 we were expecting. So block "a" modified val of global "a" as well. +// In console, only b and c are in block space. a initially is in global space(a = 100), and when a = 10 line is run, a is not created in block space, but replaces 100 with 10 in global space itself. ``` -* If one has same named variable outside the block, the variable inside the block *shadows* the outside variable. -* So, a is reassigned to 10. Since both refers to same memory space i.e GLOBAL SPACE. **This happens only for var** +- If one has same named variable outside the block, the variable inside the block _shadows_ the outside variable. +- So, a is reassigned to 10. Since both refers to same memory space i.e GLOBAL SPACE. **This happens only for var** ### Instead of var let us use let + ``` //code example 5 @@ -569,13 +590,13 @@ Outputs: > 20 -> 100 // this was what we were expecting in this first place. Both b's are in separate spaces (one in Block(20) and one in Script(another arbitrary mem space)(100)) +> 100 // this was what we were expecting in this first place. Both b's are in separate spaces (one in Block(20) and one in Script(another arbitrary mem space)(100)) -* In the Scope, we have b in two places. The b outside of the block is in *Script* SCOPE (seperate memory space for let and const) -* The b inside the block is in *Block* scope. -* Thus, when in Block scope, 20 is printed and 100 when outside. -* This concept is called "Shadowing". -* It is also true for *const* declarations. +- In the Scope, we have b in two places. The b outside of the block is in _Script_ SCOPE (seperate memory space for let and const) +- The b inside the block is in _Block_ scope. +- Thus, when in Block scope, 20 is printed and 100 when outside. +- This concept is called "Shadowing". +- It is also true for _const_ declarations. ### Same logic is true even for functions @@ -589,12 +610,14 @@ x(); console.log(c); ``` + Output: + > 10 > 100 -### __What is Illegal Shadowing?__ +### **What is Illegal Shadowing?** ``` // code example 6 @@ -610,10 +633,10 @@ Outputs: > Uncaught SyntaxError: Identifier 'a' has already been declared -* We cannot shadow let with var. But it is valid to shadow a let using a let. -* However, we can shadow var with let. -* All scope rules that work in function are same in arrow functions too. -* Since var is function scoped, it is not a problem with the code below. +- We cannot shadow let with var. But it is valid to shadow a let using a let. +- However, we can shadow var with let. +- All scope rules that work in function are same in arrow functions too. +- Since var is function scoped, it is not a problem with the code below. ``` // code example 7 @@ -626,9 +649,10 @@ function x() { ``` # Episode 10 : Closures in JS + ### Important Interview Question -**Closure :** Function bundled together with its lexical environment/scope. +**Closure :** Function bundled together with its lexical environment/scope. ``` JS is a weird language. You can pass functions as parameters to another function, assign a variable to an entire function, or even return a function. @@ -646,14 +670,16 @@ console.log(z); // value of z is entire code of function y. ``` -When functions are returned from another fun, they still maintain their lexical scope. -- When y is returned, not only is the fun returned but the entire closure (fun y + its lexical scope) is returned and put inside z. So when z is used -somewhere else in program, it still remembers var a inside x() +When functions are returned from another fun, they still maintain their lexical scope. + +- When y is returned, not only is the fun returned but the entire closure (fun y + its lexical scope) is returned and put inside z. So when z is used + somewhere else in program, it still remembers var a inside x() ### Uses of Closure -Module Design Pattern, Currying, Functions like once(fun that can be run only once), memoize, maintaining state in async world, setTimeout, iterators... -# Episode 11 : setTimeout + Closures Interview Question +Module Design Pattern, Currying, Functions like once(fun that can be run only once), memoize, maintaining state in async world, setTimeout, iterators... + +# Episode 11 : setTimeout + Closures Interview Question #### Time, tide and Javascript wait for none @@ -666,76 +692,77 @@ function x() { console.log("This is Hari"); } x(); - - ``` - > This is Hari - - > 1 //after waiting 3 seconds (3000ms) - - We expect JS to wait 3 sec, print 1 and then go down and print the string. But JS prints string immediately, waits 3 sec and then prints 1. - - - The fun inside setTimeout forms a closure (remembers reference to i). So wherever fun goes it carries this ref along with it. - - setTimeout takes this callback function & attaches timer of 3000ms and stores it. Goes to next line without waiting and prints string. - - After 3000ms runs out, JS takes function, puts it into call stack and runs it. - - #### Print 1 after 1 sec, 2 after 2 sec till 5 : Tricky interview question - - We assume this has a simple approach as below - - ``` - function x() { - for(var i = 1; i<=5; i++){ + +``` + +> This is Hari + +> 1 //after waiting 3 seconds (3000ms) + +We expect JS to wait 3 sec, print 1 and then go down and print the string. But JS prints string immediately, waits 3 sec and then prints 1. + +- The fun inside setTimeout forms a closure (remembers reference to i). So wherever fun goes it carries this ref along with it. +- setTimeout takes this callback function & attaches timer of 3000ms and stores it. Goes to next line without waiting and prints string. +- After 3000ms runs out, JS takes function, puts it into call stack and runs it. + +#### Print 1 after 1 sec, 2 after 2 sec till 5 : Tricky interview question + +We assume this has a simple approach as below + +``` +function x() { + for(var i = 1; i<=5; i++){ + setTimeout(function() { + console.log(i); + }, i*1000); + } + console.log("This is Hari"); + } + x(); + +``` + +> This is Hari + +> 6 + +> 6 + +> 6 + +> 6 + +> 6 + +- This happens because of closures. When setTimeout stores the function somewhere and attaches timer to it, the fun remembers its reference to i, **not value of i** +- All 5 copies of fun point to same reference of i. +- JS stores these 5 functions, prints string and then comes back to the functions. By then the timer has run fully. And due to looping, the i value became 6. And when the + callback fun runs the variable i = 6. So same 6 is printed in each log +- **To stop this from happening, use let instead of var** as let has black scope. For each iteration, the i is a new variable altogether(new copy of i). +- Everytime setTimeout is run, the inside fun forms closure with new variable i + +#### Using let instead of var is the best option. But if asked to use var only..? + +``` +function x() { + for(var i = 1; i<=5; i++){ + function close(i) { setTimeout(function() { - console.log(i); - }, i*1000); - } - console.log("This is Hari"); - } - x(); - - ``` - - > This is Hari - - > 6 - - > 6 - - > 6 - - > 6 - - > 6 - - - This happens because of closures. When setTimeout stores the function somewhere and attaches timer to it, the fun remembers its reference to i, **not value of i** - - All 5 copies of fun point to same reference of i. - - JS stores these 5 functions, prints string and then comes back to the functions. By then the timer has run fully. And due to looping, the i value became 6. And when the - callback fun runs the variable i = 6. So same 6 is printed in each log - - **To stop this from happening, use let instead of var** as let has black scope. For each iteration, the i is a new variable altogether(new copy of i). - - Everytime setTimeout is run, the inside fun forms closure with new variable i - - #### Using let instead of var is the best option. But if asked to use var only..? - - ``` - function x() { - for(var i = 1; i<=5; i++){ - function close(i) { - setTimeout(function() { - console.log(i); - }, i*1000); - // put the setT fun inside new function close() - } - close(i); // everytime you call close(i) it creates new copy of i. Only this time, it is with var itself! + console.log(i); + }, i*1000); + // put the setT fun inside new function close() } - console.log("This is Hari"); + close(i); // everytime you call close(i) it creates new copy of i. Only this time, it is with var itself! } - x(); - - ``` - + console.log("This is Hari"); + } + x(); + +``` + ## Only the important new concepts -- Closures are used in encapsulation and data hiding. +- Closures are used in encapsulation and data hiding. ``` (without closures) @@ -745,7 +772,7 @@ function increment(){ count++; } -in this code, anyone can access count and change it. +in this code, anyone can access count and change it. (with closures) -> put everything into a function @@ -767,15 +794,15 @@ function counter() { console.log(count); } } -var counter1 = counter(); //counter fun has closure with count var. +var counter1 = counter(); //counter fun has closure with count var. counter1(); // increments counter -Above code is not good and scalable for say, when you plan to implement decrement counter at a later stage. +Above code is not good and scalable for say, when you plan to implement decrement counter at a later stage. To address this issue, we use constructors Adding decrement counter and refactoring code: -function Counter() { //constructor function. Good coding would be to capitalize first letter of ctor fun. +function Counter() { //constructor function. Good coding would be to capitalize first letter of ctor fun. var count = 0; this.incrementCounter = function(){ //anonymous function count++; @@ -795,11 +822,13 @@ counter1.decrementCounter(); // returns 1 2 1 ``` + ### Disadvantages of closure + - Overconsumption of memory when using closure as everytime as those closed over variables are not garbage collected till program expires. -So when creating many closures, more memory is accumulated and this can create memory leaks if not handled. -- **Garbage collector** : Program in JS engine or browser that frees up unused memory. In highlevel languages like C++ or JAVA, garbage collection is left to the -programmer, but in JS engine its done implicitly. + So when creating many closures, more memory is accumulated and this can create memory leaks if not handled. +- **Garbage collector** : Program in JS engine or browser that frees up unused memory. In highlevel languages like C++ or JAVA, garbage collection is left to the + programmer, but in JS engine its done implicitly. ``` function a() { @@ -808,19 +837,20 @@ function a() { console.log(x); } } - + var y = a(); // y is a copy of b() - y(); - ``` - Once a() is called, its element x should be garbage collected ideally. But fun b has closure over var x. So mem of x cannot be freed. - Like this if more closures formed, it becomes an issue. To tacke this, JS engines like v8 and Chrome have smart garbage collection mechanisms. - Say we have var x = 0, z = 10 inabove code. When console log happens, x is printed as 0 but z is removed automatically. + y(); +``` + +Once a() is called, its element x should be garbage collected ideally. But fun b has closure over var x. So mem of x cannot be freed. +Like this if more closures formed, it becomes an issue. To tacke this, JS engines like v8 and Chrome have smart garbage collection mechanisms. +Say we have var x = 0, z = 10 inabove code. When console log happens, x is printed as 0 but z is removed automatically. # Episode 14 : First class and Anonymous functions (there is no Episode 13 idk why lol) -#### Function statement : Just your normal function definition +#### Function statement : Just your normal function definition ``` function a() { @@ -841,17 +871,20 @@ b(); ``` **Difference btw function statement and expression is Hoisting** + - You can put "a();" before "function a()" and it will still work. But putting "b();" before "var b = function()" throws a typeError. -- Why? During mem creation phase a is created in memory and function assigned to a. But b is created like a variable (b:undefined) and until code reaches the function() -part, it is still undefined. So it cannot be called. +- Why? During mem creation phase a is created in memory and function assigned to a. But b is created like a variable (b:undefined) and until code reaches the function() + part, it is still undefined. So it cannot be called. #### Function Declaration : Exactly same as function statement #### Anonymous Function : A function without a name -- They don't have their own identity. So an anony function without code inside it results in an error. + +- They don't have their own identity. So an anony function without code inside it results in an error. - Anony functions are used when functions are used as values eg. the code sample for function expression above #### Named Function Expression : Same as Function Expression but function has a name instead of being anonymous + ``` var b = function xyz() { console.log("b called"); @@ -860,17 +893,21 @@ b(); // prints "b called" properly xyz(); // Throws ReferenceError:xyz is not defined. ``` + > xyz function is not created in global scope. So it can't be called. -#### Parameters vs Arguments +#### Parameters vs Arguments + ``` -var b = function(param1, param2) { // labels/identifiers that get the arg values +var b = function(param1, param2) { // labels/identifiers that get the arg values console.log("b called"); } b(arg1, arg2); // arguments - values passed inside function call ``` + #### First Class Function aka First Class Citizens + - You can pass functions inside a function as arguments(WOW!) ``` @@ -878,7 +915,7 @@ var b = function(param1) { console.log(param1); // prints " f() {} " } b(function(){ - + }); this can also be done: @@ -895,28 +932,31 @@ you can return a function from a function: var b = function(param1) { return function() { - - } + + } } -console.log(b()); //we log the entire fun within b. +console.log(b()); //we log the entire fun within b. ``` + #### Arrow Functions (latest in ES6 (ECMAScript 2015) -> coming in future lecture # Episode 15 : Callbacks and Event Listeners **Callback Function :** Functions are first class citizens (see prev lecture) ie. take a fun A and pass it to another fun B. Here, A is a callback function -- JS is a synchronous and singlethreaded language. But due to callbacks, we can do async things in JS. + +- JS is a synchronous and singlethreaded language. But due to callbacks, we can do async things in JS. > setTimeout(function () {}, 1000) -> here the anony function is a callback function as it is passed to setT and called sometime later in code after certain time (here 1000ms). + - This is how we do async things. JS is a synch language, but it doesn't wait 1 sec for setT to finish before going to code below it. It stores the function, attaches timer -and goes down the code. + and goes down the code. ``` setTimeout(function () { console.log("timer"); }, 5000); - + function x(y) { console.log("x"); y(); @@ -935,12 +975,13 @@ x(function y() { - In the call stack, first x and y are present. After completion, they go away and stack is empty. Then after 5 seconds(from beginning) anonymous suddenly pops up in stack ie. setTimeout - All 3 functions are executed through call stack. If any operation blocks the call stack, its called **blocking the main thread** -- Say if x() takes 30 sec to run, then JS has to wait for it to finish as it has only 1 call stack/1 main thread. *Never block main thread*. +- Say if x() takes 30 sec to run, then JS has to wait for it to finish as it has only 1 call stack/1 main thread. _Never block main thread_. - **Always use async for functions that take time eg. setTimeout** -**Event Listener** +**Event Listener** - When we create a button in HTML and attack a clickListener in JS : + ``` in index.html @@ -952,76 +993,86 @@ document.getElementById("clickMe").addEventListener("click", function xyz(){ //w console.log("Button clicked"); }); ``` - Suppose we want to increase count by 1 each time button clicked. - - Use global variable (not good as anyone can change it) - - ``` - let count = 0; - document.getElementById("clickMe").addEventListener("click", function xyz(){ - console.log("Button clicked", ++count); + +Suppose we want to increase count by 1 each time button clicked. + +- Use global variable (not good as anyone can change it) + +``` +let count = 0; +document.getElementById("clickMe").addEventListener("click", function xyz(){ + console.log("Button clicked", ++count); }); - ``` +``` + - Use closures for data abstraction - ``` - function attachEventList() { //creating new fun for closure - let count = 0; - document.getElementById("clickMe").addEventListener("click", function xyz(){ - console.log("Button clicked", ++count); //now callback fun forms closure with outer scope(count) +``` +function attachEventList() { //creating new fun for closure + let count = 0; + document.getElementById("clickMe").addEventListener("click", function xyz(){ + console.log("Button clicked", ++count); //now callback fun forms closure with outer scope(count) }); } attachEventList(); ``` -#### Garbage Collection and removeEventListeners -- Event listeners are heavy as they form closures. So even when call stack is empty, EventListener won't free up memory allocated to *count* as it doesn't know -when it may need *count* again. +#### Garbage Collection and removeEventListeners + +- Event listeners are heavy as they form closures. So even when call stack is empty, EventListener won't free up memory allocated to _count_ as it doesn't know + when it may need _count_ again. - **So we remove event listeners when we don't need them (garbage collected)** -- onClick, onHover, onScroll all in a page can slow it down heavily. +- onClick, onHover, onScroll all in a page can slow it down heavily. # Episode 16 : Asynchronous JS and Event Loops > Note that call stack will execeute any execeution context which enters it. Time, tide and JS waits for none. TLDR : Call stack has no timer **Browser has JS Engine which has Call Stack which has Global exec context, local exec context etc** -- But browser has many other *superpowers* - Local storage space, Timer, place to enter URL, Bluetooth access, Geolocation access and so on + +- But browser has many other _superpowers_ - Local storage space, Timer, place to enter URL, Bluetooth access, Geolocation access and so on - Now JS needs some way to connect the callstack with all these superpowers. This is done using **Web APIs** ### WebAPIs + None of the below are part of Javascript! These are extra superpowers that browser has. Browser gives access to JS callstack to use these powers. + > setTimeout(), DOM APIs, fetch(), localstorage, console (yes, even console.log is not JS!!), location and so many more.. -- setTimeout() : Timer function +- setTimeout() : Timer function - DOM APIs : eg.Document.xxxx ; Used to access HTML