Closures: Line by Line explanation of “[removed] Good Parts” example?

后端 未结 4 694
花落未央
花落未央 2020-12-13 22:43

I\'m reading \"Javascript: The Good Parts\" and am totally baffled by what\'s really going on here. A more detailed and/or simplified explanation would be greatly appreciate

4条回答
  •  囚心锁ツ
    2020-12-13 23:21

    I think this is a very common source of confusion for newcomers to JavaScript. First I would suggest checking out the following Mozilla Dev article for brief introduction on the topic of closures and lexical scoping:

    • Mozilla Dev Center: Working with Closures

    Let's start with the bad one:

    var add_the_handlers = function (nodes) {
    // Variable i is declared in the local scope of the add_the_handlers() 
    // function. 
       var i;
    
    // Nothing special here. A normal for loop.
       for (i = 0; i < nodes.length; i += 1) {
    
    // Now we are going to assign an anonymous function to the onclick property.
           nodes[i].onclick = function (e) {
    
    // The problem here is that this anonymous function has become a closure. It 
    // will be sharing the same local variable environment as the add_the_handlers()
    // function. Therefore when the callback is called, the i variable will contain 
    // the last value it had when add_the_handlers() last returned. 
               alert(i);
           }
       }
    
    // The for loop ends, and i === nodes.length. The add_the_handlers() maintains
    // the value of i even after it returns. This is why when the callback
    // function is invoked, it will always alert the value of nodes.length.
    };
    

    We can tackle this problem with more closures, as Crockford suggested in the "good example". A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. In JavaScript, the environment of the closure consists of any local variables that were in-scope at the time that the closure was created:

     // Now we are creating an anonymous closure that creates its own local 
     // environment. I renamed the parameter variable x to make it more clear.
     nodes[i].onclick = function (x) {
    
         // Variable x will be initialized when this function is called.
    
         // Return the event callback function.
         return function (e) {
             // We use the local variable from the closure environment, and not the 
             // one held in the scope of the outer function add_the_handlers().
             alert(x);
         };
     }(i); // We invoke the function immediately to initialize its internal 
           // environment that will be captured in the closure, and to receive
           // the callback function which we need to assign to the onclick.
    

    Rather than having the callbacks all sharing a single environment, the closure function creates a new environment for each one. We could also have used a function factory to create a closure, as in the following example:

    function makeOnClickCallback (x) {
       return function (e) {
          alert(x);
       };
    }
    
    for (i = 0; i < nodes.length; i += 1) {
       nodes[i].onclick = makeOnClickCallback(i);
    }
    

提交回复
热议问题