Javascript learning notes on functions (3) : closures and references

  • 2020-03-30 04:19:53
  • OfStack

One of the most important features of Javascript is the use of closures. Because of the use of closures, the current scope can always access the external scope. Because Javascript has no block-level scope, only function scope, the use of closures is closely related to functions.

Simulated private variable


function Counter(start) {
    var count = start;
    return {
        increment: function() {
            count++;
        },
        get: function() {
            return count;
        }
    }
}
var foo = Counter(4);
foo.increment();
foo.get(); // 5

Here Counter returns two closures: the function increment and get. Both functions maintain access to the Counter scope, so they can always access the variable count defined in the Counter scope.

How private variables work

Because Javascript cannot assign values and references to scopes, in the example above, there is no way to access the internal private variable count directly from the outside. The only way to access it is by defining a closure.


var foo = new Counter(4);
foo.hack = function() {
    count = 1337;
};

The code above does not change the value of the count variable in the Counter scope, because a hack is not defined in Counter. The above code will only create or override the global variable count.

Closure within a loop

One of the easiest mistakes to make is to use closures in loops.


for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i); 
    }, 1000);
}

The code above does not output 0 to 9, but 10 times in a row.
The above anonymity will always keep a reference to the variable I. When the call to the console.log function starts output, this is the end of the loop and the variable I is already 10.
To avoid the above errors, we need to create a copy of the variable I value each time we loop.

Avoid misquoting

In order to replicate the values of the variables in the loop, the best way is to add an anonymous immediate function to the outer layer.


for(var i = 0; i < 10; i++) {
    (function(e) {
        setTimeout(function() {
            console.log(e); 
        }, 1000);
    })(i);
}

This external anonymous function takes the loop variable I as the first parameter and copies its value to its own parameter e.
External anonymous functions pass parameter e to setTimeout, so setTimeout has a reference to parameter e. And the value of this parameter e will not change because of the external loop.

Another way to achieve the same effect is to return an anonymous function in an anonymous function within setTimeout:


for(var i = 0; i < 10; i++) {
    setTimeout((function(e) {
        return function() {
            console.log(e);
        }
    })(i), 1000)
}

Additionally, you can do this with the bind method.


for(var i = 0; i < 10; i++) {
    setTimeout(console.log.bind(console, i), 1000);
}

At the end of the article, let's summarize:

(1) closure is a design principle, which simplifies the user's invocation by analyzing the context and enables the user to achieve his purpose without knowing it.
(2) the mainstream articles on closure analysis on the Internet are actually running counter to the closure principle. If you need to know the details of the closure in order to use it well, the closure is a design failure.
(3) study as little as possible.


Related articles: