Last active
          February 5, 2016 01:58 
        
      - 
      
 - 
        
Save mfdj/e831f0354ba818d81eec to your computer and use it in GitHub Desktop.  
    A very subtle detail of Javascript closures is understanding *when* a closed over symbol's value is read for use inside the closure body. Surprisingly the value isn't captured when the closure is defined, so the scope of the symbol can mutate the symbol at any point before the closure is called.
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | function makeProblems(count) { | |
| var problems = []; | |
| for (var i = 0; i < count; i++) { | |
| var problematic = function(runId) { | |
| console.log(runId + ' executed with i as: ' + i); // <-- `i` is bound to makeProblems scope | |
| }; | |
| problems.push(problematic); | |
| problematic('immediate #' + i); | |
| } | |
| i = 666; // obvious evil: since `i` scoped to makeProblems all closures will see this value | |
| return problems; | |
| } | |
| function makeSolutions(count) { | |
| var solutions = []; | |
| for (var i = 0; i < count; i++) { | |
| var solved = (function(i) { // <-- `i` is bound to the Immediately Invoked Function Expressions's scope (not makeSolutions scope) | |
| return function(runId) { | |
| console.log(runId + ' executed with i as: ' + i); // <-- also bound to the IIFE's scope | |
| }; | |
| })(i); // <-- current value of `i` is passed into IIFE scope | |
| solutions.push(solved); | |
| solved('immediate #' + i); | |
| } | |
| i = 0.666; // not so evil! | |
| return solutions; | |
| } | |
| function runAll(run) { | |
| for (var i = 0, len = run.length; i < len; i++) { | |
| run[i]('later #' + i); | |
| } | |
| } | |
| console.log("\n~~~~~~ problems ~~~~~~"); | |
| runAll(makeProblems(3)); | |
| console.log("\n~~~~~~ solutions ~~~~~~"); | |
| runAll(makeSolutions(3)); | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | ~~~~~~ problems ~~~~~~ | |
| immediate #0 executed with i as: 0 | |
| immediate #1 executed with i as: 1 | |
| immediate #2 executed with i as: 2 | |
| later #0 executed with i as: 666 | |
| later #1 executed with i as: 666 | |
| later #2 executed with i as: 666 | |
| ~~~~~~ solutions ~~~~~~ | |
| immediate #0 executed with i as: 0 | |
| immediate #1 executed with i as: 1 | |
| immediate #2 executed with i as: 2 | |
| later #0 executed with i as: 0 | |
| later #1 executed with i as: 1 | |
| later #2 executed with i as: 2 | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment
  
            
I used to run into this all the time when I had a lot of event handlers to add to a
NodeList. Then I learned about jQuery and promptly forgot.