I am binding a function to an html element.
there is some data in loop which is changing on each iteration
data = {
networkId: networkId,
network_avatar: network_avatar,
network_user_name: network_user_name,
}
Here I am binding it:
$("#element"+i).bind(function(){
change(data);
}
The function is:
function change(data){
console.log(data);
}
There should be the different data in data variable on each iteration.
But the it always contains the content of last iteration.
Why jQuery changes the data that is already binded with change() function
First of all, don't use global variables named "data" or "window" or anything else like this. If the declaration of your variable data is somewhere in vision area use "var" bareword.
When the event handler is called, it calls the "change" function and sending the current value of data in it. What you need, is to declare own data for each handler. And you should use "var" for it. Like:
$("#element"+i).bind(function(){
var currentDataValue = new CopyData(data);
change(currentDataValue);
}
function CopyData(object) {
var data = {};
for (var val in object)
data[val] = object[val];
return data;
}
I guess it should help. But i'm not too sure.
Try nesting the function within another function to create a closure. The trick with a closure is that you must have two nested functions, an inner function and an outer function. The inner function will possess a copy of the outer functions variables & parameters, in a sense inheriting its scope. In my example bindClick serves as the outer function, while the anonymous function within the call to $.click() serves as the inner function. This results in the anonymous inner function retaining the data object passed into the bindClick() method as a parameter. When we run this in a loop we essentially end up with 10 closures that remember the data object they were created with.
Live Example: http://jsfiddle.net/cDwEk/1/
function bindClick(data){
$("#element" + data.myProp).click(function(){
//anonymous function will remember state of outer functions variables.
alert(data.myProp);
});
}
//ForLoop
for(var i = 0; i < 10; i++){
var data = {myProp:i};
//Pass function to another function to create closure.
bindClick(data);
}
Related
In my naive concept, a closure is simply a function return by another function, which preserve the scope of the outer function after it returns:
var factory = function(y){
var x = 2;
return function(){
console.log(x+y);
}
}
var closure1 = factory(2);
closure1(); // output 4
var closure2 = factory(10);
closure1(); // output 4
closure2(); // output 12
Though I do not understand why adding event handler in loop will create closures? (As shown in MDN) The event handler does not explicitly be returned, this is not the concern in this problem.
Then I came across another page, and at around Code snippet #2:, it said
The onclick function would create a closure if it referenced variables in its scope, but it doesn’t.
Does that mean that in the loop
nodes[i].onclick = function () { return false; }; is not closures
But if I changed it into
nodes[i].onclick = function () { console.log(i); return false; };
Then it becomes closure?
Combined the parts above, my concept to create a closure are
It needs to be a function returned in another function, or the callback function which attached in another function
The inner function MUST somehow access outer function's scope
Is it true that a closure is created iff 1 & 2 are satisfied?
a closure is simply a function return by another function, which preserve the scope of the outer function after it returns
Close.
It is a function which still has references pointing to it after the function that it was created inside has finished.
Returning it is one way to preserve a reference to it.
Though I do not understand why adding event handler in loop will create closures?
The reference is passed to the event handling code. This preserves it after the function which passed it there has finished.
Does that mean that in the loop …
Yes, it does.
It needs to be a function returned in another function, or the callback function which attached in another function
No. The reference can go anywhere, so long as it is preserved.
var obj = {};
function create() {
var foo = 1;
obj.bar = function() {
console.log(foo++);
};
}
create();
obj.bar();
obj.bar();
obj.bar();
obj.bar();
The inner function MUST somehow access outer function's scope
Yes
I am pretty new in JavaScript and I am studying the following topics: closure and IIFE (Immediately-invoked function expression).
So I have the following example related to the closure concept, it is very commented:
/* Classical example as far as why closure can make your code look hard to anticipate, but understanding how works is "simple"
*/
function buildFunctions() {
var arr = []; // Create an empty array
for (var i = 0; i < 3; i++) {
/* Add a new function to this array, identical functions but are 3 differents functions:
*/
arr.push(
function() { // It is not invoking the function, it is just creating it
console.log(i); // i= 0, 1, 2
}
)
}
return arr;
}
var fs = buildFunctions(); // Call the build() function that put the 3 functions inside the array
/* When these functions are actually invoked and it looks at the 'i' variable they use the OUTER REFERENCE inside their execution context. So what will be the values? You might expect that the values will be 0, 1, 2 but this is wrong because at the end of the for loop inside the buildFunctions() function the value of the 'i' variable is 3. So when the anonymous functions inside the arrays are invoked they use the OUTER REFERENCE and the CLOSURE CONCEPT to access to the memory space related to the popped of fbuildFunctions() function that contain the variables of this function, and here the 'i' value is 3 !!!
N.B: Many people think that the result should be 0,1,2 because they think that when the function is pushed into the array it is invoked but it is not !!! The function is invoked here:
*/
fs[0](); // Invoke the first function inside the array, the value is 3
fs[1](); // Invoke the second function inside the array, the value is 3
fs[2](); // Invoke the third function inside the array, the value is 3
/* What have I to do if I want this works? (I want that the first function return 0, the second return 1 and the third return 3).
In order to preserve the value of 'i' for the inner anonymous function I am going to need a separate execution context for each of the functions that I am pushing into the array. I need a parent scope that holds the current values of 'i' variable as the loop goes on. So, the only way to get an execution context is to execute a function. To execute a function on the fly I use IIFE concept.
In this way every time that the loop runs, differently from the previous example, the anonymous inner function is executed passing to it the current value of the 'i' variable. This value is so stored in the 'j' variable in the execution context of the current performed anonymous inner function.
So at first time pass 0, at the second time pass 1, at the third time pass 3 and these 3 values are stored in the 'j' variable of the related execution context.
*/
function buildFunctions2() {
var arr = []; // Create an empty array
for (var i = 0; i < 3; i++) {
arr.push(
(function(j) {
return function() {
console.log(j); // print the current value
}
}(i)) // I use IIFE concept to invoke the function passing the current value of the 'i' variable
)
}
return arr;
}
var fs2 = buildFunctions2(); // Call th build() function that put the 3 functions inside the array
/*
When these functions are performed don't use closure concept because it have not to use the outer reference but use the 'j' value inside the current function execution context.
*/
fs2[0]();
fs2[1]();
fs2[2]();
I have perfectly clear how the closure works but I have some doubts about the second example of the previous example, the one related to the buildFunctions2() function.
So the first example show the closure concept and the fact that, following the outer reference of each performed functions the program reach the memory space related to the variable of the buildFunctions() also if its execution context was popped off the execution context stack. So the result will be always the same for all the 3 functions, and it will be 3.
This is perfectly clear for me.
The second example intend to obtain the values 0, 1 and 3 when I perform the 3 functions putted inside the array.
To obtain this behavior the buildFunctions2() perform a for loop that put a function inside the current element of the array using the IIFE concept, in fact:
for (var i = 0; i < 3; i++) {
arr.push(
(function(j) {
return function() {
console.log(j); // print the current value
}
}(i)) // I use IIFE concept to invoke the function passing the current value of the 'i' variable
)
}
That, from what I have understand, it means that each time that enter in the for loop a new anonymous function is added to the array and performed passing to it the 'i' value as parameter. So in this way I am not using the closure concept because no my functions print the 'j' values that are in the context of these anonymous functions. Is it my reasoning correct?
The thing that I can't understand is: if the function is added to the array and performed, why have I also to add:
fs2[0]();
fs2[1]();
fs2[2]();
to obtain the result in the FireBug console? If I remove these 3 lines that invoke the function associated to all the elements of my array I obtain no result.
This seems strange to me because, from what I have understand, using the IIFE, I add a function to the array and I automatically perform it passing to it the current 'i' value (that is 0,1,2) so why after have I to explicitly perform the functions?
What am I missing?
If you look at this part of the code:
(function(j) {
return function() {
console.log(j);
}
}(i))
You'll notice that there are two functions. The outer one is an IIFE, and will be executed immediately when this part of the code is run.
What this outer function does is define another function (the inner one), which uses the value of j that is local to the outer function (passed as a parameter). This function, however, is not executed (like in the first example), and just returned, to be executed later when you run fs2[0]().
Examples of the different between definition and execution:
function fn1(a) { } // defines a function named fn1, does not execute it
fn1(123); // executes the function defined above
fn2 = function(a) { } // defines an anonymous function, does not execute it, then stores it in fn2
fn2(234); // executes the function defined above
(function(a) { } )(345); // defines an anonymous function, and executes it right away: that's an IIFE
This JavaScript code for a Google Chrome Extension.
It works, but I wonder about one thing. It's in the for loop that iterates an associative array and utilizes its values in a Chrome function.
This works just fine:
var links =
{
apps: 'chrome://apps/',
bookmarks: 'chrome://bookmarks/',
history: 'chrome://history',
...
};
for (var link in links)
{
(function()
{
var href = links[link];
document.querySelector('#' + link).addEventListener('click', function() { chrome.tabs.create({ url: href }); });
})();
}
But with some changes it suddenly doesn't (changes are highlighted)
var href = links[link]; Look -----v
[...].addEventListener('click', function() { chrome.tabs.create({ url: links[link] }); });
Also I have to use the (function() { })(); pattern (I don't know the name), otherwise it also doesn't work.
Question
Why does this only work when using both the pattern and the variable copying? Please explain to me how JavaScript processes variables in a way that these contraptions are required.
There is no special scope in a for loop, so the variable is overwritten on each iteration when you do
for (var link in links) {
var href = links[link];
element.addEventListener('click', function() {
chrome.tabs.create({ url: href });
});
}
Note that the click happens later, when the for loop has completed, and because there is no new scope created inside the for loop, the variable changes on each iteration, and by the time you click the element, the href variable inside the event handler callback is the last value it was set to.
What's really happening is that any function declaration will create a new scope, so the variable isn't being overwritten on each iteration, and an Immediately Invoked Function Expression is such a function declaration, and it keeps the value of the variable constant because it creates a new scope
for (var link in links) {
(function() { // new scope, variables inside this isn't changed on next iteration
var href = links[link];
element.addEventListener('click', function() {
chrome.tabs.create({ url: href });
});
})();
}
The scope of a variable declared with var is its current execution
context, which is either the enclosing function or, for variables
declared outside any function, global.
When you create a reference to a function, like you do when adding that event-listener, the js interpreter preserves any variable references it finds inside that function, preventing those references from being garbage-collected.
In the first snippet, the preserved reference is a reference to a string, called href. Since this string is declared inside the self-executing anonymous function (the one you declare just within the for-loop), a new reference is created and preserved for each run of that function. Although each reference is named 'href', each reference is actually a unique variable, unique to that run of the anonymous function.
Now in the second snippet, there are two references inside your event listener function: 'link' and 'links,' but those variables are declared in the outer-scope, (from the code provided, it appears to be global, but I'm betting there's some function(){ declared above, off-screen)... because this variable is declared only once, in the same scope as the for loop, the anonymous function inside the for loop is actually always referring to the same object as the other copies. Since the for-loop changes the value referred to by 'link' every time it loops, and every binding you created is looking at the same instance of 'link' and 'links', every function you bound will always wind up referring to the last link in the list (unless you could click so fast that you hadn't completed the for-looping when you clicked, then it would point to whichever link the for loop was currently working on.)
(Edit: This behavior is actually pretty useful, btw - you can use it to emulate "public/private properties" seen in other languages, and to insulate properties from being changed by external code, like this:
var MyCounter = Counter();
MyCounter.Increment();
MyCounter.Increment();
MyCounter.Increment();
console.log(MyCounter.GetCount());
function Counter() {
// count is a locally-scoped variable, inaccessible to the outside world
var count = 0;
// The object below is what's going to be assigned to MyCounter
// the functions hold references to count, so it won't be garbage-collected
// count will also be unique to each run of Counter()
return {
Increment : function() {
count++;
},
GetCount : function() {
return count;
}
}
};
end edit)
The pattern you're referring to is called a "closure", and it's the source of endless JavaScript confusion for lots of folks.
When you create a new function inside a function, a reference to the execution state of the current function is captured and saved for later execution of the created function. The problem with doing so in a loop is that only one closure is created for any given containing function, so by the time you get to executing any of the created functions, the state saved in the closure is pointing to the last item in the loop.
Mozilla has a great explanation of the whole concept here, including a section specifically on your issue.
To add to the answer of adeneo, this article explains the closures and especially the scenario where the scope of the outer function's variable values changes.
How come in the following code my update business function always updates the input with the final value in the array
for (var i = 0; i < results.length; i++) {
var place = results[i];
var input = $("<input/>").change(function(){update_business(place.name)});
...
}
function update_business(value){
$('#business input').val(value);
}
The problem here is that all those event handler functions are going to share exactly the same "place" variable; there's only one. Relative to the event handlers it's like a global variable.
You can write a separate function to help:
function makeHandler(place) {
return function() {
update_business(place.name);
};
}
Then you can call it in the loop:
var input = $('<input/>').change(makeHandler(place));
The function returns another function, which is the thing that'll actually be used as the event handler. Because the variable "place" from the loop is passed in as an argument to the "makeHandler" function, it's a unique copy of "place" at a particular iteration through the loop. Thus, each event handler has it's very own "place".
Your inner function has closure to the outer variable itself, not a copy of its value.
You need to pass it by value by not using the closed over variable, but a new one of whoms lifespan is briefer.
(function(j) {
var place = results[j];
...
})(i);
Here the value of i is passed to the self invoking anonymous function as the j argument, and j will always be what i was at the time of that function being called.
.val() will replace the value instead of appending the value.
try using .append if you wish to add on to your current value.
documentation here.
The following program returns "local" and, according to the tutorial Im reading, it is designed to demonstrate the phenomenon ofclosure`
What I don`t understand is why, at the end, in order to call parentfunction, it assigns it to the variable "child" and then calls "child."
Why doesn`t it work by just writing parentFunction(); at the end?
var variable = "top-level";
function parentFunction() {
var variable = "local";
function childFunction() {
print(variable);
}
return childFunction;
}
var child = parentFunction();
child();
parentFunction() returns another function which you assign to var child. Then, you call child() to invoke the function returned by the call to parentFunction().
Running just parentFunction(); at the end wouldn't do anything useful because you would just discard its return value which is a function. But this would work:
parentFunction()();
See this fiddle: http://jsfiddle.net/USCjn/
Update: A simpler example:
function outer() { // outer function returns a function
return function() {
alert('inner function called');
}
}
x = outer(); // what is now in x? the inner function
// this is the same as saying:
// x = function() {
// alert('inner function called');
// }
x(); // now the inner function is called
See this fiddle: http://jsfiddle.net/bBqPY/
Functions in JavaScript can return functions (that can return functions (that can return functions ...)). If you have a function that returns another function then it means that when you call the outer function what you get is the inner function but it is not called yet. You have to call the value that you got as a function to actually run the body of the inner function. So:
x = f();
means - run a function f and store what it returns (which may be a string, a number, an object, an array, or a function) in x. But this:
x = f()();
means - run a function f, expect it to return a function and run that returned function as well (the second parentheses) and store in x what the returned function returned.
The function f here is a higher order function because it returns another function. Functions can also take another functions as arguments. One of the most powerful ideas of functional programming languages in general and JavaScript in particular is that functions are just normal values like arrays or numbers that can be returned and passed around.
You have to first grasp the idea of higher order functions to understand closures and the event system in JavaScript.
2016 Update
Note that currently this:
function outer() {
return function() {
alert('inner function called');
}
}
can be written as:
let outer = () => () => alert('inner function called');
using the ES6 arrow function syntax.
The amazing part about closures is that an inner function (in this case, childFunction) can refer to variables outside of its scope (in this case, variable). parentFunction doesn't return the result of childFunction, but an actual reference to the function!
This means that when you do the following...
var child = parentFunction();
...now, child has a reference to childFunction, and childFunction still has access to any variables it had when the function was created, even if they no longer exist.
In order to have parentFunction call childFunction, you'd need to change your code as follows:
From...
return childFunction;
To:
return childFunction();
Douglas Crockford (Pioneer of JSON, among other things) has a whole article devoted to closures, and scoping in javascript, and it would be well worth it to check out his other articles on javascript.
The point that is being demonstrated is that the function that was returned and assigned to child is still referencing the variable that was declared inside parentFunction instead of the one that was declared outside where child() is being invoked.
The only way to create a variable scope in javascript is in a function body. Normally the variable inside the parentFunction would have been discarded after the function returned.
But because you declared a function inside parentFunction that referenced variable in that scope and passed it out of parentFunction, the variable in the parentFunction is retained via the reference made in the new function.
This protects variable from outside manipulation except by functions that closed around it inside parentFunction.