|
| 1 | +Topic : Closures |
| 2 | + |
| 3 | +1. LET KEYWORD |
| 4 | + |
| 5 | +let allows you to declare variables that are limited in scope to the block, statement, or |
| 6 | +expression on which it is used. This is unlike the var keyword, which defines a variable |
| 7 | +globally, or locally to an entire function regardless of block scope. |
| 8 | + |
| 9 | +1.1. Scoping Rules |
| 10 | + |
| 11 | +Variables declared by let have their scope in the block for which they are defined, as |
| 12 | +well as in any contained sub-blocks. In this way, let works very much like var. The |
| 13 | +main difference is that the scope of a var variable is the entire enclosing function: |
| 14 | +function varTest() { |
| 15 | + var x = 1; |
| 16 | + if (true) { |
| 17 | + var x = 2; // same variable! |
| 18 | + console.log(x); // 2 |
| 19 | + } |
| 20 | + console.log(x); // 2 |
| 21 | +} |
| 22 | +function letTest() { |
| 23 | + let x = 1; |
| 24 | + if (true) { |
| 25 | + let x = 2; // different variable |
| 26 | + console.log(x); // 2 |
| 27 | + } |
| 28 | + console.log(x); // 1 |
| 29 | +} |
| 30 | + |
| 31 | +Let in for loop – Consider the following for loop. |
| 32 | +for(var a = 1; a < 5; a++){ |
| 33 | + setTimeout(function(){ |
| 34 | + console.log(a)}, 1000); |
| 35 | +} |
| 36 | +The loop will print 5 5 5 5 instead of 1 2 3 4. The short answer for this phenomena |
| 37 | +is, that the for loop executes first, then it looks for the a value, which is 5, and then |
| 38 | +outputs four times, one for each loop iteration. |
| 39 | +for (let a = 1; a < 5; a++) { |
| 40 | + setTimeout(function () { |
| 41 | + console.log(a) |
| 42 | + }, 1000); |
| 43 | +} |
| 44 | +This loop will print 1 2 3 4. Every round of let creates a new variable and bounds it |
| 45 | +with the closure.Let a gets a new binding for every iteration of the loop. This means |
| 46 | +that every closure, if function is created in loop captures a different a instance. |
| 47 | +EXTRA: |
| 48 | +You can read about let from the links below - |
| 49 | +https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let |
| 50 | +https://www.geeksforgeeks.org/difference-between-var-and-let-in-javascript/ |
| 51 | + |
| 52 | + |
| 53 | +2. EXECUTION CONTEXT AND LEXICAL ENVIRONMENT |
| 54 | + |
| 55 | + |
| 56 | +2.1. Execution Context |
| 57 | + |
| 58 | +When your code runs in the JavaScript Engine. Each statement of your code is |
| 59 | +executed in a certain Execution Context.In JavaScript environment there are 2 main |
| 60 | +types of Execution Context. First is Global Execution Context,when your code is |
| 61 | +initially run even if it’s spread across to a page using a <script /> tag, JavaScript |
| 62 | +creates one Global Execution Context in which your code was placed in when they |
| 63 | +execute and runs inside the browser. Second is the Function Execution Context |
| 64 | +from the word itself it was created when you invoked the function that you define. |
| 65 | +Each time you invoked a function it will create a new Function Execution Context. |
| 66 | +var message = ‘Hello there’; |
| 67 | +function foo(message) { |
| 68 | + bar(message); |
| 69 | +} |
| 70 | +function bar(message) { |
| 71 | + console.log(message); |
| 72 | +} |
| 73 | +foo(message); |
| 74 | +Initially Execution Context Stack is empty. |
| 75 | +When this code runs, JavaScript engine create one Global Execution Context and |
| 76 | +push it to Execution Context Stack. |
| 77 | +When we call the function foo, Global Execution Context was paused because |
| 78 | +JavaScript is a single threaded environment they can only execute one code at a |
| 79 | +time. After that JavaScript engine will create a new Function Execution Context for |
| 80 | +foo and push it into Execution Context Stack. |
| 81 | +When foo function is executed we invoked the bar inside foo definition. JavaScript |
| 82 | +engine paused the execution context in foo function and creates a new Function |
| 83 | +Execution Context for bar and pushed it into stack. |
| 84 | +After the bar was finished executing it will popped out in the Execution Context |
| 85 | +Stack and go back to foo and resume its execution. Same process will applied to the |
| 86 | +foo until we finished and go back to the Global Execution Context and resume the |
| 87 | +execution. |
| 88 | + |
| 89 | +2.2. Lexical Environment |
| 90 | + |
| 91 | +Consider the following code |
| 92 | +var a = ‘a’; |
| 93 | +function foo() { |
| 94 | + var b = ‘b’; |
| 95 | + function bar() { |
| 96 | + var c = ‘c’; |
| 97 | + console.log(c); // You can access me here. |
| 98 | + console.log(b); // You can access me too.. |
| 99 | + console.log(a); // You can also access me.. |
| 100 | + } |
| 101 | + bar(); |
| 102 | +} |
| 103 | +foo(); |
| 104 | +When this code runs initially a Global Environment was created and a and foo was |
| 105 | +stored in that. When we invoked the function foo below a new environment was |
| 106 | +created and stored the variable b in foo environment which is only visible to bar |
| 107 | +function because bar is an inner function in foo environment. When invoking the |
| 108 | +foo() we also called the bar() function which is also creates a new environment for |
| 109 | +their definition. |
| 110 | +Whenever we call a function, a new function execution context is created and |
| 111 | +pushed into execution context stack with a new associated lexical environment. |
| 112 | + |
| 113 | +Inside the bar function we do logging to checks if the variables that we create is |
| 114 | +visible and if we can access it in their environment. |
| 115 | +When variable c was logged in the bar environment, it was displayed successfully |
| 116 | +obviously because it was inside his environment. |
| 117 | +However when when we do logging the variable b and variable a it was also |
| 118 | +successfully displayed.How did this happened? |
| 119 | +This is because, In the second logging we call the variable b which is not in bar |
| 120 | +function scope. So javascript does this internally to search it in other Outer |
| 121 | +Environment until they found that variable. In our case, they found the variable b at |
| 122 | +foo function since the bar function has reference to foo function the foo function |
| 123 | +environment is not pop out in the Execution Context! When variable a was logged it |
| 124 | +was also successfully displayed because variable a is stored in the Global Execution |
| 125 | +Context. Everyone can access the Scope in the Global Execution Context. |
| 126 | + |
| 127 | +EXTRA: |
| 128 | +You can read about them from the links below - |
| 129 | +https://blog.bitsrc.io/understanding-execution-context-and-execution-stack-in-javascript1c9ea8642dd0 |
| 130 | + |
| 131 | + |
| 132 | +3. CLOSURES |
| 133 | + |
| 134 | + |
| 135 | +A closure is a feature in JavaScript where an inner function has access to the outer |
| 136 | +(enclosing) function’s variables—a scope chain. |
| 137 | +The closure has three scope chains: |
| 138 | +● it has access to its own scope—variables defined between its curly brackets |
| 139 | +● it has access to the outer function’s variables |
| 140 | +● it has access to the global variables |
| 141 | +A closure is created when an inner function is made accessible from outside of the function |
| 142 | +that created it. This typically occurs when an outer function returns an inner |
| 143 | +function. When this happens, the inner function maintains a reference to the environment |
| 144 | +in which it was created. This means that it remembers all of the variables (and their values) |
| 145 | +that were in scope at the time. The following example shows how a closure is created and |
| 146 | +used. |
| 147 | +function add(value1) { |
| 148 | + return function doAdd(value2) { |
| 149 | + return value1 + value2; |
| 150 | + }; |
| 151 | +} |
| 152 | +var increment = add(1); |
| 153 | +var foo = increment(2); |
| 154 | +// foo equals 3 |
| 155 | +From the above example, we can make following observations - |
| 156 | +Thee add() function returns its inner function doAdd(). By returning a reference to an inner |
| 157 | +function, a closure is created. |
| 158 | +“value1” is a local variable of add(), and a non-local variable of doAdd(). Non-local variables |
| 159 | +refer to variables that are neither in the local nor the global scope. “value2” is a local |
| 160 | +variable of doAdd(). |
| 161 | +When add(1) is called, a closure is created and stored in “increment”. In the closure’s |
| 162 | +referencing environment, “value1” is bound to the value one. Variables that are bound are |
| 163 | +also said to be closed over. This is where the name closure comes from. |
| 164 | + When increment(2) is called, the closure is entered. This means that doAdd() is called, with |
| 165 | +the “value1” variable holding the value one |
0 commit comments