Access outside variable in loop from Javascript closure
The problem you have here is that the variable item
changes with each loop. When you are referencing item
at some later point, the last value it held is used. You can use a technique called a closure (essentially a function that returns a function) to quickly scope the variable differently.
for (var i in this.items) {
var item = this.items[i];
$("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
$("#showcasebutton_"+item.id).click(
// create an anonymous function that will scope "item"
(function(item) {
// that returns our function
return function() {
alert(item.id);
self.switchto(item.id);
};
})(item) // immediately call it with "item"
);
}
A side note - I see that you have jQuery here. It has a helper function $.each()
that can be used with arrays, and can be a shortcut for simple for/each loops. Because of the way the scoping works in this call - you wont need to use a closure because "item" is already the parameter of the function when it was called, not stored in a var
in the parent function's scope, like was true in your example.
$.each(this.items,function(i, item) {
$("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
$("#showcasebutton_"+item.id).click(function() {
alert(item.id);
self.switchto(item.id);
});
});
Accessing variables trapped by closure
Variables within a closure aren't directly accessible from the outside by any means. However, closures within that closure that have the variable in scope can access them, and if you make those closures accessible from the outside, it's almost as good.
Here's an example:
var A = function(b) {
var c = b + 100;
this.access_c = function(value) {
// Function sets c if value is provided, but only returns c if no value
// is provided
if(arguments.length > 0)
c = value;
return c;
};
this.twain = function() {
return 2 * c;
};
};
var a_inst = new A(123);
var my_c = a_inst.access_c();
// my_c now contains 223
var my_2c = a_inst.twain();
// my_2c contains 446
a_inst.access_c(5);
// c in closure is now equal to 5
var newer_2c = a_inst.twain();
// newer_2c contains 10
Hopefully that's slightly useful to you...
Javascript closures with let variable
In the first code example, you have three different i
variables and in each iteration of the loop, callback function of setTimeout
closes over a different copy of i
variable.
In the second code example, there is only one i
variable and in each iteration of the loop, callback function of setTimeout
closes over the same i
variable.
There is only one i
variable in the second code example because you have declared it outside the loop; as a result, each iteration of the loop sees the same variable i
.
In order to get the same output in the second code example, change it as shown below:
let i = 0;
for (i = 0; i < 3; i++) {
let j = i; // save a copy of the current value of 'i'
setTimeout(() => {
console.log(j); // closure over a different 'j' variable in each iteration
}, 1000);
}
Javascript closures - variable scope question
Its because at the time item.help
is evaluated, the loop would have completed in its entirety. Instead, you can do this with a closure:
for (var i = 0; i < helpText.length; i++) {
document.getElementById(helpText[i].id).onfocus = function(item) {
return function() {showHelp(item.help);};
}(helpText[i]);
}
JavaScript doesn't have block scope but it does have function-scope. By creating a closure, we are capturing the reference to helpText[i]
permanently.
Related Topics
Regex to Match All Instances Not Inside Quotes
How to Listen to the Form Submit Event in JavaScript
Disabling and Enabling a HTML Input Button
How to Load Data from a CSV File in D3 V5
How to Close a Browser Window Without Receiving the "Do You Want to Close This Window" Prompt
How to Hide Form Code from View Code/Inspect Element Browser
How to Sort Elements by Numerical Value of Data Attribute
Detect Input Value Change with Mutationobserver
How to Use JSON File in HTML Code
What Does the "|" (Single Pipe) Do in JavaScript
Comparing Arrays of Objects in JavaScript
How to Get a Word Under Cursor Using JavaScript
Why Does JavaScript Object Show Different Values in Console in Chrome, Firefox, Safari
How to Be Notified When an Element Is Added to the Page
How to Prevent Page from Reloading After Form Submit - Jquery