ricardomol
  • Ricardomol Notes
  • Frontend
    • Javascript Toolchain
    • Javascript
      • Quirks
      • Articles
        • Function caching
        • 12 JS Tricks
      • Closures
      • Assorted
      • ES6
      • this
      • OOP
      • Async Programming
      • Functional Programming
      • Typescript
    • React
      • Patterns
        • Render props
      • React Router
    • Webpack
    • CSS
      • Resources
  • Backend
    • Python
      • Shallow copy vs deep copy
      • Classes
      • Resources
      • Python C Extensions
      • Coroutines
      • Exceptions
      • Context managers
      • One-Liners
      • Open function
      • Object introspection
      • Targeting Python 2 + 3
      • For - else
      • Comprehensions
      • Lambdas
      • __slots__ magic
      • Collections
      • Enumerate
      • Mutation
      • Map, Filter and Reduce
      • Decorators
      • Sets
      • Fluent Python summary
      • Quizes / Tips
      • Generators
    • Django
      • Generic Relations
      • FBV's vs CBV's
      • ORM
      • DRF
    • RESTful Architecture
    • Resources
  • Databases
    • Joins
    • Normalization
    • PostgreSQL
  • DevOps
    • Docker
      • 0. Resources
      • 2. Services
      • 3. Swarms
      • 5. Stacks
      • 6. Deploy your app
    • CI
      • CI with Django
    • CD
    • PaaS
    • WSGI servers
    • Django
      • Django Deployment
    • Modern DevOps with Django
  • Git
    • Git
  • Comp Sci
    • Big O Notation
    • Patterns
    • Programming paradigms
  • Assorted
    • TCP vs UDP
    • Tests
    • MongoDB
    • Node
      • Resources
    • Go
    • HTTP vs HTTP2
    • GraphQL
    • Books
    • Vim
    • IPv4 vs IPv6
    • Regex
    • Redis
    • Celery
      • Brokers
    • Caching
  • SECURITY
    • Security
Powered by GitBook
On this page
  • Closures
  • Use case
  • Solutions
  1. Frontend
  2. Javascript

Closures

Closures

Use case

var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener('click', function() {
      console.log('You clicked element #' + i);
   });
}

The code prints two times You clicked element #NODES_LENGTHwhere NODES_LENGTH is the number of the nodes retrieved.

The value of the variables in closures isn’t static, hence the value of i isn’t the value at the time the handler was added (0 for the first button in the list, 1 for the second, and so on). At the time the handler will be executed, on the console will be printed the current value of the variable i, that is equal to the length of the nodes list.

Solutions

First solution: use an IIFE to create another closure so that the value of i will be the one expected:

var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener('click', (function(i) {
      return function() {
         console.log('You clicked element #' + i);
      }
   })(i));
}

Second solution: move the function outside the loop. :

function handlerWrapper(i) {
   return function() {
      console.log('You clicked element #' + i);
   }
}

var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener('click', handlerWrapper(i));
}

Previous12 JS TricksNextAssorted

Last updated 6 years ago