0

i read MDN pages about const, let, var. the summary of that is before ES2015 we have only global scope and function scope.in [this MDN page][1] there is an example of the benefits of block scope; that shows: instead of using closure concept to save related data for a function, like for loop iteration number, defined the loop variable as let. if the let keyword is only for block scoping how provide us this functionality? are other programming languages have this concept?

        let divClassX = document.querySelectorAll('.x');
        for (let j = 0; j < 2; j++) {
            divClassX[j].onclick = function (event) {
                console.log('class x div\'s x ' + j)
            }
        }

above code has the same functionality as :

        let divClassX = document.querySelectorAll('.x');
        for (var j = 0; j < 2; j++) {
            divClassX[j].onclick = (function (j) {
                return function (event) {
                    console.log('class x div\'s x ' + j)
                }
            })(j)
        }

I assumed that some functionality like that exists so the blow code must work like above but when I clicked on div1 or div2 both times I get 2 but expected one when clicked on div 1 and two when I clicked on div2.

        let div1 = document.querySelector('#div1');
        let div2 = document.querySelector('#div2');

        let i = 1;
        div1.onclick = function (event) {
            console.log(i);
        }
        i = i + 1;
        div2.onclick = function (event) {
            console.log(i);
        }

what concept exists that I don't know? [1]: https://developer.mozilla.org/en-US/docs/Glossary/IIFE

kankan256
  • 210
  • 1
  • 4
  • 18

2 Answers2

1

It's more about what scope the variable is defined in than the order in which it's modified.

In your last example, let i occurs in the global scope. Each function you create as an event listener creates its own scope whose parent scope is the global scope. It doesn't matter what i's value was when the function was created, it's the structure of the scope chain that matters. JavaScript looks for variables in increasingly large scopes going up the "chain" of parent scopes. For both functions, i will resolve to the global scope when accessed at the time the function is called, not when the function is created.

As for loops with let, I believe part of the design goal for let was to make loop/event handler (or other nested functions) behaviour more intuitive, and provide an easy way to avoid the common issue where each event handler references the last value of i as opposed to the value when the function was created (i.e. at each iteration of the loop).

In other words, in ES2015 there is a separate scope for each iteration of the loop, and let assigns variables to that scope, not to the surrounding function or the global scope like var. Also when a nested function is called (a function that's inside the for loop), it hits the "iteration" scope first when looking up the scope chain, so it sees the i as it was at the time of iteration.

Gus Hogg-Blake
  • 2,393
  • 2
  • 21
  • 31
0

It's called closure.

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

In your last snippet

console.log(i);

doesn't print a copy, but the actual variable i (reference), that is initialized with

let i = 1;

and modified with

i = i + 1;
jabaa
  • 5,844
  • 3
  • 9
  • 30
  • For clarity, the quote above seems to be talking about ES5 - in ES6 (ES2015) and later, scopes are created by blocks as well as functions, and they're not just lexical, for example, in a for loop, each iteration creates its own scope – Gus Hogg-Blake Dec 01 '21 at 18:13