Understanding JavaScript Closures

Closures are considered the basic front-end interview questions, but I read a lot of articles about closures blog, but I feel that many of the ideals of closures are still divergent, and now the online understanding of closures is generally two.

  • Some articles argue that closures must return the method of the nested function that uses the local variables of the outside function in order to be called a closure, with two conditions.
    1. function nesting, the internal function to use the external function of the local variables.
    2. the internal function must return.
  • Some articles believe that as long as the function nested internal function used external local variables is closed, do not return to the internal function.

Let’s take a look at what the definition of closures really is, and then analyze the misconceptions I had about closures at different stages of learning js. The definition of closure in advanced programming is this: “A closure is a function that has permission to access a variable in the scope of another function. “There is no mention here that this function has to be RETURNED out. We are looking at the definition of closures in Language Essentials with a very misleading code example to explain closures.

var quo = function(status){
    return{
        get_status:function(){
        	return status;
        }
    }
}

var myQuo = quo("amazed");
document.writeln(myQuo.get_status());

Even if quo returns, but get_status method still enjoys the privilege of accessing the quo object’s status property, get_status method is not accessing a copy of the parameter, it is accessing the parameter itself, just possible, because the function can access the context in which it was created, which is known as a closure.

This is the most common case of explanation for many articles explaining closures, so it leads newcomers to look at this explanation for the first time to produce a misleading, that it is necessary to return the function, but we look at the “javascript language essentials” this explanation in the last paragraph emphasizes that the function can access the context in which it was created, the emphasis is on access to the local variables of the external function.

And use this example because this example is a more complex application of closure, because you are in the function nesting, the internal function can only be executed in the external function to run in the global variables can not be run, if we want to run in the global a more easily understood method is.

var get_status;
var quo = function(status){
    get_status=function(){
    	return status;
    }
}

quo("amazed");
document.writeln( get_status());

So is this closure? Optimization of the above code using js can return function code simplified a lot. So in my understanding as long as the function calls the external function variables are closed, and the reason for the introduction of the closure are used that case because that is considered the classic complex application of the closure, so the basic introduction of the closure will introduce that case, so instead of misleading the students just learning closure must return out, the following I am talking about my understanding of the closure stepped in the pit.

At first I understood the closure is anonymous self-executing function, anonymous self-executing function is the following code.

(function(){})()
//or
var dem=(function(){}())

This anonymous self-execution is of course most used in jQuery.

(function ($) {})(jQuery)

This is often seen in jQuery plugins. The purpose of this is that $ variables may be defined as other values in the page, and the jQuery object is assigned a local $ variable in order to avoid conflicts with the $ symbol. This way, the global $ is not affected.
There is another usage.

var a = [];
for (var i = 0; i < 10; i++) {
    a[i] = function () {
    	console.log(i);
	};
}
a[6]();

Because js does not have a block scope so that i is actually a global variable, so a so the method inside the i are 10, to solve this problem can be used in es6 let, but some browsers do not support es6, Google has supported the let keyword, now the practice is to write with es6 through the node plug-in to convert to es5 write, but also with a solution.

 var a = [];
 for (var i = 0; i < 10; i++) {
     (function(i){
         a[i] = function () {
         	console.log(i);
         };
     })(i)
 }
 a[6]();

The method in the anonymous self-execution assigns i to a local variable i so the value of a is a call to the anonymous method in the local variable i. Here also used the closure, so at the time I misunderstood that the closure is actually the conversion of global variables to local variables. I also answered the same way during the interview, and the interviewer was confused.

The second stage of the misunderstanding is the function that must be returned, so for the above anonymous execution method I said with a firm hand that it is not a closure! The interviewer was confused again during the interview.

The interviewer was confused again. I read “advanced javascript programming” and “javascript language essentials” to slowly get a comprehensive understanding of closures. This is my understanding of the closed package may also have understanding of the wrong place, welcome the message correction, originally the process of growth is the understanding of something from one-sided to slowly comprehensive process, and growth should be discussed together with the debate we elaborate their views in order to recognize a more comprehensive. Here are a few cases of complex applications of closures.

Closures in the actual project application to put it bluntly is a function to operate some variables frequently, but this variable is defined in the function in the function each time the function is run to re-declare the allocation of memory space a trouble two to feel the consumption of memory (used C# and java should be very familiar with garbage disposal mechanism, js garbage disposal mechanism similar not much detail) but set to global variables and will pollute global variables, mentioned in the js performance optimization try not to pollute the global variables, the natural way out of the outside set into a function, which is the closure, but also to ensure the flexibility of the internal function can not be limited to the scope of the outer closure, return the function of the way out, the outer function does not want to use the variable storage and also run alone once, then the anonymous self-executing way The need for OK has evolved and led to the final combination of writing methods. One of the drawbacks of closures is that the called variables will always be stored in memory and not released, and this drawback has different solutions in the actual project requirements.

The first scenario, the module

 var serial_maker = function () {
     var prefix = '';
     var seq = 0;
     return {
         set_prefix: function (p) {
         	prefix = new String(p)
         },
         set_seq: function (s) {
         	seq = s;
         },
         gensym: function () {
             var result = prefix + seq;
             seq += 1;
             return result;
         }
     }
 }
 var seqer = serial_maker();
 seqer,set_prefix('Q');
 seqer.set_seq(1000);
 var unique = seqer.gensym(); // Q1000

This is also very common closure, the intention is not to declare the prefix and seq as global variables, and pollution global variables, in fact, in the variable life cycle perspective and global variables are the same, prefix and seq will always exist in memory until the page is closed, javascript advanced programming said that the variable will be released after the function is executed.
The global variables will remain in memory until the browser is closed, the book also mentions that the browser is closed when the dom object variables used to assign null, because the browser does not seem to be able to release the dom object, this point I am a little fuzzy remember not clear, I review the javascript advanced programming when I saw in a separate write again random. To solve the shortcomings of this closure just add a layer of anonymous self-executing function on the outside.

(function () {
    var serial_maker = function () {
        var prefix = '';
        var seq = 0;
        return {
            set_prefix: function (p) {
            	prefix = new String(p)
            },
            set_seq: function (s) {
            	seq = s;
            },
            gensym: function () {
                var result = prefix + seq;
                seq += 1;
                return result;
            }
        }
    }
})();

The raw declaration cycle of the variables used in the closure is actually followed by the life cycle of the previous function that calls the function, the prefix and seq in this example are released after the execution of the anonymous function. This is also in the usual writing js when trying to write a layer of anonymous outside since the implementation of a layer will not pollute the global variables, the second in the anonymous function after the execution of the variables inside the release, relatively in the performance optimization to do a little contribution and optimization it!

The second scenario

The same can be done with anonymous closures on event binding, performance is determined to exist, you are setting global variables and closures actually a memory footprint. Unavoidable.

Scene 3: Corridorization

Corridor is a function of the parameters passed to another function operation, generally used in the call to ajax after the success of the data tied to the page when used, but with the emergence of promise, in fact, Corridor used very little. The following is a more complex application.

Function.prototype.curry = function () {
    var slice = Array.prototype.slice,
        args = slice.apply(arguments), // Because arguments are not really arrays, but only an array-like object, so here we have to convert arguments to arrays
        that = this;
    debugger;
    return function () {
        return that.apply(null, args.concat(slice.apply(arguments)))
    }
};
var add = function () {
    var total = 0;
    for(var i = 0; i < arguments.length; i++){
    	total += arguments[i];
    }
    return total;
};
var add1 = add.curry(1);
document.writeln(add1(6)); // 7

Leave a Reply