Learning Javascript, why do these two functions behave differently? - javascript

Learning Javascript and can't figure out why these two functions are different. I saw this example (I added names to the functions):
var txt = ["a","b","c"];
for (var i = 0; i < 3; ++i ) {
setTimeout((function myBind(msg) {
return function myAlert() { alert(msg); }
})(txt[i]), 1000);
}​
I see that a function that calls alert is being returned. So I thought, why not just return it directly:
var txt = ["a","b","c"];
for (var i = 0; i < 3; ++i ) {
setTimeout( function() { alert(txt[i]);} ,1000);
}​
This ends up alerting 'undefined.' I understand that it's because it's trying to access txt[3] because after one second the loop has finished and i has been set to 3, but I don't understand how the original setup avoided this problem.

Example 1
The closures execute the script instantly and also allow you to pass a parameter inside
which is stored and remains stored inside that function. parameter==param
(function(param){})(parameter)
In your example the function returns another function which will be executed by setTimeout.
(function(param){
return function(){
alert(param)
}
})(parameter)
And as you passed the parameter previously to the function it will return the right value.
Example 2
The setTimeout is called 3 times very fast but the parameter is not stored anywhere
so it takes the last value know from txt & i and as the loop is ended before the setTimeout is executed the value is 3
basically in the first example you store every txt[i] inside each function you create with those closures.
In the second one you don't store the txt[i]'s anywhere. you just tell the setTimout function to alert txt[i], which after 1second is the last one created by the for loop.

You need to read up about closures. See this answer How do JavaScript closures work? to understand them.

In the first version, txt[i] has been bound to a new variable, msg, which is a different location for each function being created.
In the second version, i is the same location for each of the functions because i's scope is further up; there isn't a new i variable being created each time through the loop.

This is a concurrency problem.
setTimeout creates a "thread" for each execution, but won't evaluate the function until the timeout expires.
so, after a second, when the first timeout expires, your for loop has ended (with i having 3 as value), so accessing the txt[i] returns undefined.
Try printing the value of i inside the function with console.log

Related

why javascript use call by reference , sometimes :D [duplicate]

This code is supposed to pop up an alert with the number of the image when you click it:
for(var i=0; i<10; i++) {
$("#img" + i).click(
function () { alert(i); }
);
}
You can see it not working at http://jsfiddle.net/upFaJ/. I know that this is because all of the click-handler closures are referring to the same object i, so every single handler pops up "10" when it's triggered.
However, when I do this, it works fine:
for(var i=0; i<10; i++) {
(function (i2) {
$("#img" + i2).click(
function () { alert(i2); }
);
})(i);
}
You can see it working at http://jsfiddle.net/v4sSD/.
Why does it work? There's still only one i object in memory, right? Objects are always passed by reference, not copied, so the self-executing function call should make no difference. The output of the two code snippets should be identical. So why is the i object being copied 10 times? Why does it work?
I think it's interesting that this version doesn't work:
for(var i=0; i<10; i++) {
(function () {
$("#img" + i).click(
function () { alert(i); }
);
})();
}
It seems that the passing of the object as a function parameter makes all the difference.
EDIT: OK, so the previous example can be explained by primitives (i) being passed by value to the function call. But what about this example, which uses real objects?
for(var i=0; i<5; i++) {
var toggler = $("<img/>", { "src": "http://www.famfamfam.com/lab/icons/silk/icons/cross.png" });
toggler.click(function () { toggler.attr("src", "http://www.famfamfam.com/lab/icons/silk/icons/tick.png"); });
$("#container").append(toggler);
}
Not working: http://jsfiddle.net/Zpwku/
for(var i=0; i<5; i++) {
var toggler = $("<img/>", { "src": "http://www.famfamfam.com/lab/icons/silk/icons/cross.png" });
(function (t) {
t.click(function () { t.attr("src", "http://www.famfamfam.com/lab/icons/silk/icons/tick.png"); });
$("#container").append(t);
})(toggler);
}
Working: http://jsfiddle.net/YLSn6/
Most of the answers are correct in that passing an object as a function parameter breaks a closure and thus allow us to assign things to functions from within a loop. But I'd like to point out why this is the case, and it's not just a special case for closures.
You see, the way javascript passes parameters to functions is a bit different form other languages. Firstly, it seems to have two ways of doing it depending on weather it's a primitive value or an object. For primitive values it seems to pass by value and for objects it seems to pass by reference.
How javascript passes function arguments
Actually, the real explanation of what javascript does explains both situations, as well as why it breaks closures, using just a single mechanism.
What javascript does is actually it passes parameters by copy of reference. That is to say, it creates another reference to the parameter and passes that new reference into the function.
Pass by value?
Assume that all variables in javascript are references. In other languages, when we say a variable is a reference, we expect it to behave like this:
var i = 1;
function increment (n) { n = n+1 };
increment(i); // we would expect i to be 2 if i is a reference
But in javascript, it's not the case:
console.log(i); // i is still 1
That's a classic pass by value isn't it?
Pass by reference?
But wait, for objects it's a different story:
var o = {a:1,b:2}
function foo (x) {
x.c = 3;
}
foo(o);
If parameters were passed by value we'd expect the o object to be unchanged but:
console.log(o); // outputs {a:1,b:2,c:3}
That's classic pass by reference there. So we have two behaviors depending on weather we're passing a primitive type or an object.
Wait, what?
But wait a second, check this out:
var o = {a:1,b:2,c:3}
function bar (x) {
x = {a:2,b:4,c:6}
}
bar(o);
Now see what happens:
console.log(o); // outputs {a:1,b:2,c:3}
What! That's not passing by reference! The values are unchanged!
Which is why I call it pass by copy of reference. If we think about it this way, everything makes sense. We don't need to think of primitives as having special behavior when passed into a function because objects behave the same way. If we try to modify the object the variable points to then it works like pass by reference but if we try to modify the reference itself then it works like pass by value.
This also explains why closures are broken by passing a variable as a function parameter. Because the function call will create another reference that is not bound by the closure like the original variable.
Epilogue: I lied
One more thing before we end this. I said before that this unifies the behavior of primitive types and objects. Actually no, primitive types are still different:
var i = 1;
function bat (n) { n.hello = 'world' };
bat(i);
console.log(i.hello); // undefined, i is unchanged
I give up. There's no making sense of this. It's just the way it is.
It's because you are calling a function, passing it a value.
for (var i = 0; i < 10; i++) {
alert(i);
}
You expect this to alert different values, right? Because you are passing the current value of i to alert.
function attachClick(val) {
$("#img" + val).click(
function () { alert(val); }
);
}
With this function, you'd expect it to alert whatever val was passed into it, right? That also works when calling it in a loop:
for (var i = 0; i < 10; i++) {
attachClick(i);
}
This:
for (var i = 0; i < 10; i++) {
(function (val) {
$("#img" + val).click(
function () { alert(val); }
);
})(i);
}
is just an inline declaration of the above. You are declaring an anonymous function with the same characteristics as attachClick above and you call it immediately. The act of passing a value through a function parameter breaks any references to the i variable.
upvoted deceze's answer, but thought I'd try a simpler explanation. The reason the closure works is that variables in javascript are function scoped. The closure creates a new scope, and by passing the value of i in as a parameter, you are defining a local variable i in the new scope. without the closure, all of the click handlers you define are in the same scope, using the same i. the reason that your last code snippet doesn't work is because there is no local i, so all click handlers are looking to the nearest parent context with i defined.
I think the other thing that might be confusing you is this comment
Objects are always passed by reference, not copied, so the self-executing function call should make no difference.
this is true for objects, but not primitive values (numbers, for example). This is why a new local i can be defined. To demonstrate, if you did something weird like wrapping the value of i in an array, the closure would not work, because arrays are passed by reference.
// doesn't work
for(var i=[0]; i[0]<10; i[0]++) {
(function (i2) {
$("#img" + i2[0]).click(
function () { alert(i2[0]); }
);
})(i);
}
In the first example, there is only one value of i and it's the one used in the for loop. This, all event handlers will show the value of i when the for loop ends, not the desired value.
In the second example, the value of i at the time the event handler is installed is copied to the i2 function argument and there is a separate copy of that for each invocation of the function and thus for each event handler.
So, this:
(function (i2) {
$("#img" + i2).click(
function () { alert(i2); }
);
})(i);
Creates a new variable i2 that has it's own value for each separate invocation of the function. Because of closures in javascript, each separate copy of i2 is preserved for each separate event handler - thus solving your problem.
In the third example, no new copy of i is made (they all refer to the same i from the for loop) so it works the same as the first example.
Code 1 and Code 3 didn't work because i is a variable and values are changed in each loop. At the end of loop 10 will be assigned to i.
For more clear, take a look at this example,
for(var i=0; i<10; i++) {
}
alert(i)
http://jsfiddle.net/muthkum/t4Ur5/
You can see I put a alert after the loop and it will show show alert box with value 10.
This is what happening to Code 1 and Code 3.
Run the next example:
for(var i=0; i<10; i++) {
$("#img" + i).click(
function () { alert(i); }
);
}
i++;
You'll see that now, 11 is being alerted.
Therefore, you need to avoid the reference to i, by sending it as a function parameter, by it's value. You have already found the solution.
One thing that the other answers didn't mention is why this example that I gave in the question doesn't work:
for(var i=0; i<5; i++) {
var toggler = $("<img/>", { "src": "http://www.famfamfam.com/lab/icons/silk/icons/cross.png" });
toggler.click(function () { toggler.attr("src", "http://www.famfamfam.com/lab/icons/silk/icons/tick.png"); });
$("#container").append(toggler);
}
Coming back to the question months later with a better understanding of JavaScript, the reason it doesn't work can be understood as follows:
The var toggler declaration is hoisted to the top of the function call. All references to toggler are to the same actual identifier.
The closure referenced in the anonymous function is the same (not a shallow copy) of the one containing toggler, which is being updated for each iteration of the loop.
#2 is quite surprising. This alerts "5" for example:
var o;
setTimeout(function () { o = {value: 5}; }, 100);
setTimeout(function () { alert(o.value) }, 1000);

Chrome Extension callback functions and concurrency

I'm learning to code Chrome Extensions and I'm curious about passing parameters into asynchronous functions and a possible concurrency issue. Let me give you an example:
function updateActiveTab(param1)
{
chrome.tabs.query({active: true, currentWindow: true}, function(tabs)
{
onUpdatingTab(tabs[0].id, param1);
});
}
function onUpdatingTab(tabID, param1)
{
console.log("Tag ID=" + tabID + ", param=" + param1);
}
So, lets assume that the first time my updateActiveTab() method is called with param1=1 and the call to chrome.tabs.query() takes a while. In the meantime, while chrome.tabs.query() is still being processed, my updateActiveTab() method is called again with param1=2. What would happen when the first call to chrome.tabs.query() returns and begins processing its callback function? Will param1 be 1 or 2?
I'm obviously looking to pass my param1 as 1, and 2, and so on, to its function's respective calls.
The short answer is that you will win. Read up on JavaScript closures to really understand what's going on here. I'll hit the highlights so you get the idea.
The reference to param1 inside of onUpdatingTab forces param1 into a closure. The closure keeps the value of param1 alive as long as it is needed by calls to inner functions. The scenario you describe will create two different closures, one for each call to onUpdatingTab.
Here's an example adapted from JavaScript: The Good Parts that illustrates this aspect of closures. This function takes an array of DOM nodes and adds an onclick handler that displays the ordinal of the node:
function add_the_handlers = function (nodes) {
var helper = function(i) {
return function(e) { alert(i); };
};
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = helper(i);
}
}
Each call to helper returns a function where the reference to "i" is bound to the closure for that helper call. Note the semantic distinction with code that doesn't use the helper, but just does this:
nodes[i].onclick = function() { alert(i); }
Here "i" again binds to a closure, but it's the closure associated with the call to add_the_handlers, so clicking on each node displays the same value, which is the number of nodes not the ordinal. That's the last value assigned to "i".

Opening new pages with

I've tried what seems like dozens of different solutions to this all with different failures. Basically I've built an array that has a bunch of IDs in it and I and using javascript to loop through them and open pages that go through an archiving process. These need to be delayed because it takes about a minute for each one to occur. Here's what I have currently:
var i = 0
function openPage() {
while (i < Array.length) {
window.setTimeout(go(i), 60000*i;);
i++;
}
}
function go(i) {
window.open('http://localhost:12575/DD7RO2.aspx?id=' + Array[i][0]);
}
Then I call openPage from a button press.
For some reason this throws an error of "Invalid argument" at the window.setTimeout line. I can't seem to figure out why that is. Every other iteration of this that I've tried has either opened a single window (the first in the array) and stopped, or opened everything completely disregarding the timeout. I feel like this one might actually work since it's actually doing something different. Any help would be be greatly appreciated.
You are evaluating go(i) when it's passed as an argument. That function executes in the loop. Instead, you should return a function object, and that will be executed when the timer fires.
Do not do function(){go(i);}, that's a classic closure error. You would end up calling the functiongo(i) each time the event fired, but with the same, final, value of i. The scope of i is the enclosing function, so by the time the timeouts run it will have a value of Array.length - 1.
Instead something like
window.setTimeout((function (j){return function(j){go(j)}})(i), 60000*i;);
To spell that out;
(
function (j) {
var k = j;
return function() {
go(k)
}
}
)(i);
This looks confusing, but that's the way JS works.
It immediately executes a function with the value of i.
That returns a function object, but that function is in a closure in which the value of i bound at that point in time.
The function object is executed when the timeout event fires, with the value of i bound correctly.
window.setTimeout(function(){ go(i); }, 60000*i;);
Here you go!

Javascript closure

I read the () at the end of the closure will execute it immediately. So, what is the difference between these two. I saw the first usage in some code.
thanks.
for (var a=selectsomeobj(),i=0,len=a.length;i<len;++i){
(function(val){
anotherFn(val);
})(a[i]);
}
for (var a=selectsomeobj(),i=0,len=a.length;i<len;++i){
anotherFn(a[i]);
}
In this example there are no differences. In both cases, anotherFn gets executed immediately.
However, an immediate function is often used when a function is created in a loop.
Consider this example (more or less pseudo code):
for(var i from 1..10) {
elements[i].onclick = function() {
alert(values[i]);
}
}
As JavaScript has only function scope, no block scope, all the event handlers share the same i, which will have the value 10 after the loop finished. So every handler will try to alert values[10].
By using an immediate function, a new scope is introduced which "captures" the current value of the loop variable:
for(var i from 1..10) {
(function(index) {
elements[i].onclick = function() {
alert(values[index]);
}
}(i));
}
As this is sometimes hard to read, creating a standalone function which returns another function is often better:
function getHandler(value) {
return function(){alert(value);};
}
for(var i from 1..10) {
elements[i].onclick = getHandler(values[i]);
}
In both instances in your example the values do identical operations. There are other examples out there where if you're not careful to use the first method (with the self-executing anonymous function), the value of i will increment and not be passed correctly to your function.
Here's a guide, scroll down to the creating closures in loops: a common mistake section to see the problem:
https://developer.mozilla.org/en/JavaScript/Guide/Closures
the first defines a self-invoking function (which in turn executes a function), the second just executes the function. In both cases the argument passed to the is a[i].

Closures: Line by Line explanation of "Javascript: Good Parts" example?

I'm reading "Javascript: The Good Parts" and am totally baffled by what's really going on here. A more detailed and/or simplified explanation would be greatly appreciated.
// BAD EXAMPLE
// Make a function that assigns event handler functions to an array of nodes the wrong way.
// When you click on a node, an alert box is supposed to display the ordinal of the node.
// But it always displays the number of nodes instead.
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (e) {
alert(i);
}
}
};
// END BAD EXAMPLE
The add_the_handlers function was intended to give each handler a unique number (i). It fails because the handler functions are bound to the variable i, not the value of the variable i at the time the function was made:
// BETTER EXAMPLE
// Make a function that assigns event handler functions to an array of nodes the right way.
// When you click on a node, an alert box will display the ordinal of the node.
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (i) {
return function (e) {
alert(i);
};
}(i);
}
};
Now, instead of assigning a function to onclick, we define a function and immediately invoke it, passing in i. That function will return an event handler function that is bound to the value of i that was passed in, not to the i defined in add_the_handlers. That returned function is assigned to onclick.
I think this is a very common source of confusion for newcomers to JavaScript. First I would suggest checking out the following Mozilla Dev article for brief introduction on the topic of closures and lexical scoping:
Mozilla Dev Center: Working with Closures
Let's start with the bad one:
var add_the_handlers = function (nodes) {
// Variable i is declared in the local scope of the add_the_handlers()
// function.
var i;
// Nothing special here. A normal for loop.
for (i = 0; i < nodes.length; i += 1) {
// Now we are going to assign an anonymous function to the onclick property.
nodes[i].onclick = function (e) {
// The problem here is that this anonymous function has become a closure. It
// will be sharing the same local variable environment as the add_the_handlers()
// function. Therefore when the callback is called, the i variable will contain
// the last value it had when add_the_handlers() last returned.
alert(i);
}
}
// The for loop ends, and i === nodes.length. The add_the_handlers() maintains
// the value of i even after it returns. This is why when the callback
// function is invoked, it will always alert the value of nodes.length.
};
We can tackle this problem with more closures, as Crockford suggested in the "good example". A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. In JavaScript, the environment of the closure consists of any local variables that were in-scope at the time that the closure was created:
// Now we are creating an anonymous closure that creates its own local
// environment. I renamed the parameter variable x to make it more clear.
nodes[i].onclick = function (x) {
// Variable x will be initialized when this function is called.
// Return the event callback function.
return function (e) {
// We use the local variable from the closure environment, and not the
// one held in the scope of the outer function add_the_handlers().
alert(x);
};
}(i); // We invoke the function immediately to initialize its internal
// environment that will be captured in the closure, and to receive
// the callback function which we need to assign to the onclick.
Rather than having the callbacks all sharing a single environment, the closure function creates a new environment for each one. We could also have used a function factory to create a closure, as in the following example:
function makeOnClickCallback (x) {
return function (e) {
alert(x);
};
}
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = makeOnClickCallback(i);
}
It's all about closures. In the first example, "i" will be equal to "nodes.length" for every click event handler, because it uses "i" from the loop which creates the event handlers. By the time the event handler is called, the loop will have ended, so "i" will be equal to "nodes.length".
In the second example, "i" is a parameter (so a local variable). The event handlers will use the value of the local variable "i" (the parameter).
In both examples any node that's passed has an onclick event handler bound to it (just like <img src="..." onclick="myhandler()"/>, which is bad practice after all).
The difference is that in the bad example every closure (the event handler functions, that is) is referencing the exact same i variable due to their common parent scope.
The good example makes use of an anonymous function that gets executed right away. This anonymous function references the exact same i variable as in the bad example BUT since it is executed and provided with i as its first parameter, i's value is assigned to a local variable called ... eh? ... i, exactely - thus overwriting the one defined in the parent's scope.
Let's rewrite the good example to make it all clear:
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (newvar) {
return function (e) {
alert(nevar);
};
}(i);
}
};
Here we replaced i in the returned event handler function with newvar and it still works, because newvar is just what you'd expect - a new variable inherited from the anonymous function's scope.
Good luck figuring it out.
It has to do with closure.
When you do the thing in the bad example,
when you click each node, you will get the latest i value (i.e. you have 3 nodes, no matter what node you click you will get 2). since your alert(i) is bound to a reference of variable i and not the value of i at the moment it was bound in the event handler.
Doing it the better example way, you bound it to what i as at the moment that it was iterated on, so clicking on node 1 will give you 0, node 2 will give you 1 and node 3 will give you 2.
basically, you are evaluating what i is immediately when it is called at the line }(i) and it got passed to parameter e which now hold the value of what i is at that moment in time.
Btw... I think there is a typo there in the better example part... it should be alert(e) instead of alert(i).

Categories

Resources