In Javascript, variables are traditionally functional . Blocks, such as ... for loop statements, do not create a new area.
If you declare a variable with var at any point in your function (for example, in a for loop), it will be declared only once at the top of the scope thanks to hoisting , and there will be only one instance in the scope of the entire function.
This can lead to problems when calling callbacks inside a for ... loop.
// with hoisting, i is only declared once for (var i in items) { // the fn is called items.length times, before any callback is invoked _fetchItems(items[i], function() { console.log("fetched for ", items{i]); // for all callbacks, i is the same value items.length-1 // because they are called after the loop is complete }); }
Or in your example:
// with hoisting, i is only declared once for (var i = 1; i <= 5; i++) { // with hoisting, item is only declared once var item = document.createElement("li"); item.appendChild(document.createTextNode("Item " + i)); // this function will be called after the for...loop is complete // so i value is unique: 5 + 1 = 6 item.onclick = function (ev) { // => always return "Item 6 is clicked" console.log("Item " + i + " is clicked."); }; list.appendChild(item); }
Conversely, let variables are only bound to the closest block (i.e., any section of code between curly braces).
In your example, a new instance of the variable i declared for each execution of the block inside the for .... loop. i goes from 1 to 5, so there are 5 executions of the block, therefore, 5 instances of the variable.
Each of them will return the expected value "Click on element 1.", "Click on element 2", etc.