This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the purpose of a self executing function in javascript?
Hopefully quite a straight forward question:
What is the purpose of using self invoking anonymous functions? Is it simply to prevent "polluting" the global scope with variables etc.? Or are there other advantages to using them?
Out of my personal experience, other than using anonymous functions for inducing a scope, I have also used it in for-loops for closure. This can be useful when a DOM element needs to store its count and you don't have access to libraries like jQuery etc.
Let's say you have a 100 DIV elements. Clicking the first DIV element should alert 1, similarly clicking the 56th div element should alert 56.
So when creating these elements, you normally do something like this
// Assume myElements is a collection of the aforementioned div elements
for (var i = 0; i < 100; ++i) {
myElements[i].onclick = function() {
alert( 'You clicked on: ' + i );
};
}
This will alert 99, as the counter is currently 99. The value of i is not maintained here.
However, when an anonymous function is used to tackle the problem,
for (var i = 0; i < 100; ++i) {
(function(count){
myElements[count].onclick = function() {
alert( 'You clicked on: ' + count );
};
})(i);
}
Here the value of i is maintained and the correct count is displayed.
Is it simply to prevent "polluting" the global scope with variables etc.?
Pretty much. Encapsulation and avoiding as much global state as possible are good goals in themselves.
It is to create its own scope. It is not only better because you no longer "pollute" some other (global, for example) scope, it gives you guaranteed escape for name collision concerns and defense from programmers that like to poke inside internals of your functions/objects/methods too much among all the benefits. It also allows GC to easily understand that you don't need any of referenced objects anymore when function is done.
Closures in for-loops also use self invoking anonymous functions.
function attachEventsToListItems( ) {
var oList = document.getElementById('myList');
var aListItems = oList.getElementsByTagName('li');
for(var i = 0; i < aListItems.length; i++) {
var oListItem = aListItems[i];
// Watch this:
oListItem.onclick = (function(value) {
return function() {
alert(value);
}
})(i);
}
}
Related
Closures in a loop are causing me problems. I think I have to make another function that returns a function to solve the problem, but I can't get it to work with my jQuery code.
Here is the basic problem in a simplified form:
function foo(val) {
alert(val);
}
for (var i = 0; i < 3; i++) {
$('#button'+i).click(function(){
foo(i);
});
}
Naturally clicking on any of the three buttons will give an alert saying 3. The functionality I want is that clicking on button 1 will give an alert saying 1, button 2 will say 2 etc.
How can I make it do that?
See the bind method.
$('#button'+i).bind('click', {button: i}, function(event) {
foo(event.data.button);
});
From the docs:
The optional eventData parameter is
not commonly used. When provided, this
argument allows us to pass additional
information to the handler. One handy
use of this parameter is to work
around issues caused by closures
Try this code:
function foo(val) {
alert(val);
}
var funMaker = function(k) {
return function() {
foo(k);
};
};
for (var i = 0; i < 3; i++) {
$('#button'+i).click(funMaker(i));
}
Some important points here:
JavaScript is function scoped. If you want a new ('deeper') scope, you need to create a function to hold it.
This solution is Javascript specific, it works with or without jQuery.
The solution works because each value of i is copied in a new scope as k, and the function returned from funMaker closes around k (which doesn't change in the loop), not around i (which does).
Your code doesn't work because the function that you pass to click doesn't 'own' the i, it closes over the i of its creator, and that i changes in the loop.
The example could have been written with funMaker inlined, but I usually use such helper functions to make things clearer.
The argument of funMaker is k, but that makes no difference, it could have been i without any problems, since it exists in the scope of the function funMaker.
One of the clearest explanation of the 'Environment' evaluation model is found in 'Structure and Interpretation of Computer Programs', by Sussman & Abelson (http://mitpress.mit.edu/sicp/ full text available online, not an easy read) - see section 3.2. Since JavaScript is really Scheme with C syntax, that explanation is OK.
EDIT: Fixed some punctuation.
#Andy solution is the nicest. But you can also use Javascript scoping to help you save the value in your closure.
You do so by creating a new scope in your loop body by executing an anonymous function.
for (var i = 0; i < 3; i++) {
(function(){
var index = i;
$('#button'+index).click(function(){
foo(index);
});
})();
}
Since the loop body is a new scope at each iteration, the index variable is duplicated with the correct value at each iteration.
Use the .each function from jquery - I guess you a looping through similar elements - so add the click using something like:
$(element).children(class).each(function(i){
$(this).click(function(){
foo(i);
});
});
Not tested but I always use this kind structure where possible.
Or just manufacture a new function, as you describe. It would look like this:
function foo(val) {
return function() {
alert(val);
}
}
for (var i = 0; i < 3; i++) {
$('#button'+i).click(foo(i));
}
I'm pretty sure Mehrdad's solution doesn't work. When you see people copying to a temporary variable, it's usually to save the value of "this" which may be different within an inner child scope.
So lets say I have some code:
//Javascript
var elements = [];
function addNumbah1(){
var i = 1;
elements.push(i);
}
function addNumbah2(){
var i = 2;
elements.push(i);
}
And that goes on up to addNumbah999(), is it bad form to declare the i variable every time? Will that break anything? Should I do:
//Javascript
var elements = [];
var i
function addNumbah1(){
i = 1;
elements.push(i);
}
function addNumbah2(){
i = 2;
elements.push(i);
}
Short answer: NO, JS hoists all variable declarations to the top of the scope, regardless of how many times you've declared them:
var i = 0
for (var i=0;i<10;i++)
{
var j = i%2;//declared 10 times, on each iteration
}
Will be translated to
var i, j; //i is undefined at this point in the code.
for (i = 0;i<10;i++)
{
j = i%2;//declared 10 times, on each iteration
}
In your first example, you're declaring i as a variable in a function's scope, which is what you must do to avoid cluttering the global scope. The memory these variables use is allocated when the function is called, and deallocated when the function returns (roughly, closures form an exception, but that would take us to far). Consider this:
var i = 10;
function someF()
{
var i = 1;
alert(i);
}
someF();//alerts 1 <-- value of i, local to someF
alert(i);//10, global i is unchanged
But if you were to omit the var:
function someF()
{
i = 1;
alert(i);
}
You'll see that 1 is alerted twice. If JS can't find a variable declaration in the current scope, it will look in the higher scopes until a var is found. If no variable is found, JS will create one for you in the highest scope (global). Check my answer here on how implied globals work for a more detailed example, or read the MDN pages, especially the section on Name conflicts
Lastly, I'd like to add that globals, especially implied globals, are evil. Also know that the ECMA6 standard is clearly moving away from global variables and introduces support for true block-scopes. As you can see here
Oh, and if you want to check if a function uses implied globals: 'use strict'; is a great thing:
(function()
{
'use strict';
var localVar = 123;//ok
impliedGlobal = 123;//TypeError!
}());
As you can see, implied globals are not allowed. See MDN on strict mode for the full explanation
The second form, with global i might actually be a bit slower because it's defined in a higher scope, and variables defined in a higher scope take longer to resolve.
Aside from any performance considerations just stick with common guidelines unless performance is really an issue. In this case: scope your variables as narrowly as possible.
I would strongly advise you to use the first form.
The first way you did it is fine. Each instance of i would have no knowledge of the other i in the other functions.
You should read this tutorial on global versus local variables
Also, could I suggest an optimization. Why can't you just do the following to cover any number (instead of separate functions for each number)?
var elements = [];
function addNumbah(number){
elements.push(number);
}
It is okay to declare variables with same name in different functions.
Variables declared inside a function only exist in the scope of that function, so having the same variable name across different functions will not break anything.
In fact, it is good form to keep variables in as small of a scope as possible! Global variables can be difficult to manage and can create really bad bugs, especially if one function isn't done using the variable when another function tries to access it.
Specifically for simple variables, declaring
var i = 0;
every time is perfectly fine.
You can declare a variable multiple times..In your code you are declaring Variable i in different scopes here:
//Here you are declaring variable i local to addNumbah1,2 functions
var elements = [];
function addNumbah1(){
var i = 1;
elements.push(i);
}
function addNumbah2(){
var i = 2;
elements.push(i);
}
//Here v /variable i has been declared globally
var elements = [];
var i
function addNumbah1(){
i = 1;
elements.push(i);
}
function addNumbah2(){
i = 2;
elements.push(i);
}
Note that although you can declare a variable multiple times but generally its not a good programming practice as it may cause bugs/problems in your application
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why is using the JavaScript eval function a bad idea?
So I have read through MANY different methods on calling a function from a string, using window[](); and also eval();. I am wondering if for my situation (That is below) what method is exactly the right way to go ahead with, and if so, explain why. Also explain why eval(); isn't exactly a good option, a lot of people say security, but why would security be an issue if you can get any browser plugin that enables you to change the script on that page? (example: firebug for firefox)
My current code:
funcOne(target).funcTwo(x, y, z);
How would call this using the recommended window[](); way? And why can't I use this?:
eval('funcOne(target).funcTwo(x, y, z)');
I don't want your annoyance of this question being asked many times, because I cannot currently think of a way to call a, as a call it, double function.
Thanks in advance!
In Javascript the syntax a.b can be replaced with a["b"]. So in your case you can use
window["funcOne"](target)["funcTwo"](x, y, z);
where of course it makes sense only if you are using variables instead of "funcOne" and "funcTwo".
If everything is instead fixed but you simply want to delay execution you can use "thunking" with an anonymous closure with
x = function(){ return funcOne(target).funcTwo(x, y, z); };
and then you can evaluate with x() to get the desired result later.
The last example will work correctly even if the variables target and x, y and z are local to the enclosing scope because the thunking closure will "capture" them.
You should however pay attention to the fact that in Javascript the only way to create a new scope is to use a function (a block surrounded with { and } is NOT a scope like happens in C++ and other languages).
If you need to create several closures in a loop this can bite back and is a source of a quite common mistake...
for (var i=0; i<options.length; i++)
{
var menu_item = document.createElement("div");
menu_item.textContent = "Option " + i;
menu_item.onclick = function () {
// Warning this will NOT work. All divs will
// alert using the same number!
alert("Option " + i + " selected");
}
menu.appendChild(menu_item);
}
here I used a closure for the onclick event on the div, but this is not going to work because all those functions will use the very same i variable. Because in Javascript the only way to create a scope is using a function the solution is:
for (var i=0; i<options.length; i++)
{
var menu_item = document.createElement("div");
menu_item.textContent = "Option " + i;
(function(i){
menu_item.onclick = function () {
alert("Option " + i + " selected");
};
})(i); // Pass current `i` as parameter
menu.appendChild(menu_item);
}
This way the variable i inside the onclick handler will be different for each closure.
This pattern of creating a function just to call it immediately is often used in Javascript when you need to create many independent closures so it's better to know and understand it.
I'm using jQuery and I have a strange thing that I don't understand. I have some code:
for (i = 1; i <= some_number; i++) {
$("#some_button" + i).click(function() {
alert(i);
});
}
"#some_button" as the name says - they are some buttons. When clicked they should pop-up a box with it's number, correct? But they don't. If there is 4 buttons, they always pop-up "5" (buttons count + 1). Why is that so?
It has to do with JavaScript scoping. You can get around it easily by introducing another scope by adding a function and having that function call itself and pass in i:
for (var i = 1; i <= some_number; i++) {
(function(j) {
$("#some_button" + j).click(function() {
alert(j);
});
})(i);
}
This creates a closure - when the inner function has access to a scope that no longer exists when the function is called. See this article on the MDC for more information.
EDIT: RE: Self-calling functions: A self-calling function is a function that calls itself anonymously. You don't instantiate it nor do you assign it to a variable. It takes the following form (note the opening parens):
(function(args) {
// function body that might modify args
})(args_to_pass_in);
Relating this to the question, the body of the anonymous function would be:
$("#some_button" + j).click(function() {
alert(j);
});
Combining these together, we get the answer in the first code block. The anonymous self-calling function is expecting an argument called j. It looks for any element with an id of some_button with the integer value of j at the end (e.g. some_button1, some_button10). Any time one of these elements is clicked, it alerts the value of j. The second-to-last line of the solution passes in the value i, which is the loop counter where the anonymous self-calling function is called. Done another way, it might look like this:
var innerFunction = function(j) {
$("#some_button" + j).click(function() {
alert(j);
});
};
for (var i = 1; i <= some_number; i++) {
innerFunction(i);
}
You are having a very common closure problem in the for loop.
Variables enclosed in a closure share the same single environment, so by the time the click callback is called, the loop will have run its course and the i variable will be left pointing to the last entry.
You can solve this with even more closures, using a function factory:
function makeOnClickCallback(i) {
return function() {
alert(i);
};
}
var i;
for (i = 0; i < some_number; i++) {
$("#some_button" + i).click(makeOnClickCallback(i));
}
This can be quite a tricky topic, if you are not familiar with how closures work. You may to check out the following Mozilla article for a brief introduction:
Working with Closures
Because in the moment you click them, i == 5.
This is because of how closures work in JavaScript. Each of the 5 functions you are creating is basically sharing the same i variable. The value of i inside your function is not being evaluated when you are creating the function, but when the click event occurs, by which time the value of i is 5.
There are various techniques for getting around this (when this behavior isn't what you want). One (if you have a simple function, like you do here) is to use the Function constructor instead of a function literal:
$("#some_button" + i).click(new Function("alert("+i+")");
(function (some_number) {
for (i = 1; i <= some_number; i++) {
$("#some_button" + i).click(function() {
alert(i);
});
}
})(some_number);
Wrap the function outside because for speed and the fact i will keep resetting.
This is very clever code. So clever it's a question on SO. :) I'd sidestep the question altogether by dumbing the code down, just to have a chance at understanding it (or having a colleague understand it) six months from now. Closures have their place, but in this case I'd avoid them in favour of more understandable code.
Probably, I'd attach the same function to all the buttons, which would get the button from the event, strip "some_button" from the ID, and alert the result. Not nearly as pretty, but I guarantee everyone in the office could follow it at a glance.
In the question
Javascript infamous Loop issue?
the accepted answer from Christoph's says
JavaScript's scopes are
function-level, not block-level
What if Javascript's scopes are block-level, then would the Infamous Loop problem still occur? Or will there be a different (and easier) way of fixing it?
Is it as opposed to other languages, where using a { would start a new scope?
I found an answer:
Javascript 1.7 and above supports block-level scope, and Firefox 3.0 and above supports it. (See http://en.wikipedia.org/wiki/Javascript#Versions )
I tried the following code using Firefox 3.5.9:
Note that the keyword let is used, which will create a block-level scope.
ha link 1
ha link 2
ha link 3
ha link 4
ha link 5
<script type="application/javascript;version=1.7"/>
for (i = 1; i <=5; i++) {
let x = i;
document.getElementById('link' + i).onclick = function() { alert(x); return false; }
}
</script>
Sure enough, a new scope is created, with a new x in it. The anonymous function that does the alert(x) captures this scope (the whole scope chain) and remembers it, thus forming the closure. When this anonymous function is invoked, the scope is there, and when it looks for x, sure enough, the x is in that scope as 1, 2, 3, 4, 5 respectively. Try and change the let into a var and you get the infamous old problem again, because no new scope is created.
If blocks created scopes (for closures), then this would work the way people who later post a question on StackOverflow think it might work:
for (var i = 0; i < thing.length; ++i) {
var element = $('#elem' + i); // making this up randomly here
setTimeout(function() { doSomething(element); }, 100);
}
That would work because each iteration of the loop body would (probably) create a new scope, and thus a new "element". As it is, the fact that no new scope is created means that each function instantiated through the progress of the loop shares the same "element" variable, and thus the code doesn't work properly and another StackOverflow javascript question is born.
Basically, it's a way of saying the value obtained via the first setup is a 'pointer' - a reference to the value of the variable when the method is invoked. In the second instance, the value is a 'copy', not a 'pointer', so each instance has it's own value.
That's assuming I have read your question right.