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.
Related
My goal is to use closures while still writing clean code. One thing I noticed is that somehow I always end up repeating myself because one of my anonymous functions is needed in more than one case.
To this goal, I want to have these repeated functions stored in an object which I can later reuse.
Now, to my question. I've created this example http://jsfiddle.net/tiagoespinha/tTx64/ and the alert will not fire, because y is null.
However, if I inline the function, everything works fine http://jsfiddle.net/tiagoespinha/tTx64/1/
Is there a trick to work around this? How can I have it working in the first example? The variable y is still there, why can't JS catch it?
You want objects having own variables (y) and sharing functions.
What you really need is probably prototype.
function Holder() {
this.y = 5;
this.myFn();
}
Holder.prototype.myFn = function() {
alert("The value of the closure var is " + this.y);
}
new Holder();
I'd suggest the reading of Introduction to Object-Oriented JavaScript so that you don't try to rebuild OOP with just closures.
//our constructor, each instance will carry a y of 5
function Proto() {
this.y = 5;
}
//a shared function for all instances
Proto.prototype.returnedFn = function() {
alert("The value of the closure var is " + this.y);
}
//just a wrapper for the new instance call.
//I just like it this way to avoid using "new" when making instances
function newFn() {
//return a new instance
return new Proto();
}
//test it out
newFn().returnedFn();
newFn().returnedFn();
Your first example would need some kind of dynamic scoping to work. Javascript is statically scoped.
Closures allow a function to capture some local variables from the scope it's defined in. Holder.myFn isn't defined in a scope that contains variable y.
Also note that every instance of a function has its own closure. Hence it's not possible to define your function once and have it refer to different y's in different contexts. (In your second example the inner function is defined every time you call newFn, so many instances can exist, each with its own copy of y.)
I will also add an answer to my own question to report my findings.
Based on the other solutions provided and partly using the OOP solution, I found another way which also makes use of closures.
// Object prototype which takes an argument
function MyObj(abc) {
// Declare function using a closure
// and thus being able to use the argument
this.myFn = (function(){
return function() {
alert("abc is " + abc);
};
})();
}
// Then we can simply create an object with the
// desired argument and the function will behave as expected
var v = new MyObj(10);
v.myFn();
I think nobody provided this solution possibly because I omitted that I don't really want to store the values locally in the object. I simply want to pass some values in, make use of them in one function and then get rid of the object.
In this case I believe a pure OOP solution might be overkill.
Anyhow, thank you for all the proposed solutions!
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);
}
}
I click a button and there is a handler. I have never understood if I should use a closure, or let the handler be in a object. For example, in HTML I have,
<button id="b">Go</button>
<button id="c">Go</button>
and in JavaScript (with some jQuery),
var hdl=function(){
var hdl=function(){
foo+="foo"
console.log(foo)
},
foo=""
return hdl
}()
$("#b").click(hdl)
var obj={
bar:"",
hdl:function(){
this.bar+="bar"
console.log(this.bar)
}
}
var baz=function(){
obj.hdl()
}
$("#c").click(baz)
Both work. Or are there situations in which you can only use one of them?
An event handler is always a function or an object that implements the EventListener interface. I've never understood any reason to use an EventListener object rather than a function so I've only seen functions used, but you can use either.
If you choose a function, it's up to you whether you want a function to be a global function, an anonymously declared function or a function that is a property of an object. There is no "right" answer as it depends upon how you want to structure your code.
My event handlers are usually anonymously declared functions just because that's usually how I structure things and generally nothing more is needed. Simple is best so you should make it no more complicated than needed.
A closure is just a function body that survives longer than the simple execution of the function because some other function reference inside is still active. Whether to use a closure or not depends on your needs and again the structure of your code. Closures can be really handy ways of keeping some state without using global variables, but other times they aren't needed at all.
I think you're mixing up terms.
Closures are a natural result of JavaScript's scoping rules, not something you choose to create
The jQuery click event always takes a function. Whether that function is attached to an object—thereby making it a method—doesn't really matter. Depending on how that function is written, it may form a closure that affects you.
A closure is when a function "remembers" the variables in the context in which it's defined.
The classical closure example is something like this:
for(var i = 0; i < 10; i++)
$("#button" + i).click(function() { alert("you clicked button " + i); });
Most developers are surprised to learn that each button displays 10, which is the value of i when the outer scope ends. This happens because each of those functions declared in the loop has formed a closure over i. Those functions don't just get the value of i when they're declared, they get the actual i, in all its glory. That's why changing i after you create the function causes the created function to reflect the updated value of i
Situations like this are fixed by breaking the closure by passing i to a function, since function parameters are passed by value.
for(var i = 0; i < 10; i++)
(function(localI) {
$("#button" + i).click(function() { alert("you clicked button " + localI); });
)(i);
The only difference between your cases is that in one of them you are bundling your variables (foo) in an object. The following third example should make this point clear:
function hdl(variables){
variables.foo += variables.foo;
}
var obj = {foo: ""};
var baz = function(){
hdl(obj);
}
I don't think any of these alternatives is in anyway generally superior to the others. You should decide to use whatever solution is simpler and easier to understand and mantain depending on what your particular problem is.
For example, in the version using objects the variables are dinamically bound while in the version with closures they are statically bound. This means that the object version is more extensible (with inheritance, mixins, etc) while the closure version is more rigid (but simpler to reason about at compile time)
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.