I am a newbie to java script and currently reading John Resig's Pro javascript techniques . While explaining closure he refers to calls like setTimeout("otherFunction()",2000) as instances where new JS developers have problems . I could not understand why this is a problem ? Can some one explain please ?In this http://www.w3schools.com/js/js_timing.asp I am seeing a call like var t=setTimeout("alertMsg()",3000); which looks similar to me .
It's not "wrong", it's just not necessarily "right", and it's certainly not recommended.
The setTimeout() function's first parameter can be a string or a function reference / function expression.
If you pass a string it will be slower because effectively you are doing an eval() which is not recommended. More important than speed though is that the scope in which the code in the string executes may not be what you are expecting (and may not be the same in different browsers).
By passing a function reference / function expression instead these problems can be avoided.
The "right" syntax for your example is:
setTimeout(otherFunction, 2000);
Note there are no parentheses after otherFunction - if there were it would call otherFunction() immediately and pass the return value from that function to setTimeout().
If you need to pass parameters to your function you can wrap it in an anonymous function:
setTimeout(function() {
otherFunction(param1, param2);
}, 2000);
That may seem kind of clunky compared to setTimeout("otherFunction(param1,param2)", 2000) but again it avoids issues with scope of where otherFunction, param1 and param2 are defined.
The recommended approach is to use the following:
setTimeout(otherFunction, 2000);
or a closure:
setTimeout(function() {
otherFunction();
}, 2000);
Do not use the overload which takes a string as first parameter because the javascript interpreter will need to parse this string into javascript code.
And yeah, the site you have linked to http://www.w3schools.com is probably one of the worst sites out there to learn programming. It shows exactly what you shouldn't do.
Because it has to eval otherFunction() (and hence spawn a new instance of the interpreter) every time. If you provide a reference to the function, setTimeout can execute it without the necessity to spawn a new interpreter.
So use:
setTimeout(otherFunction,2000);
Anything enclosed with "" is a string so a JavaScript interpreter will generally need to parse the string.
Parsing the string is unnecessary even if it works.
If we simply use
setTimeout(alertMsg,3000);,
the interpreter is not required to do any additional (unnecessary) work, resulting in better code.
Instead of setTimeout("otherFunction()",2000), pass the function directly by doing
setTimeout(otherFunction,2000) is much better. The previous way has to do eval the string "otherFunction()".
Related
This question already has answers here:
How to execute a JavaScript function when I have its name as a string
(36 answers)
Closed 8 years ago.
I have a JavaScript variable which contains the name of a JavaScript function. This function exists on the page by having been loaded in and placed using $.ajax, etc.
Can anyone tell me how I would call the javascript function named in the variable, please?
The name of the function is in a variable because the URL used to load the page fragment (which gets inserted into the current page) contains the name of the function to call.
I am open to other suggestions on how to implement this solution.
I'd avoid eval.
To solve this problem, you should know these things about JavaScript.
Functions are first-class objects, so they can be properties of an object (in which case they are called methods) or even elements of arrays.
If you aren't choosing the object a function belongs to, it belongs to the global scope. In the browser, that means you're hanging it on the object named "window," which is where globals live.
Arrays and objects are intimately related. (Rumor is they might even be the result of incest!) You can often substitute using a dot . rather than square brackets [], or vice versa.
Your problem is a result of considering the dot manner of reference rather than the square bracket manner.
So, why not something like,
window["functionName"]();
That's assuming your function lives in the global space. If you've namespaced, then:
myNameSpace["functionName"]();
Avoid eval, and avoid passing a string in to setTimeout and setInterval. I write a lot of JS, and I NEVER need eval. "Needing" eval comes from not knowing the language deeply enough. You need to learn about scoping, context, and syntax. If you're ever stuck with an eval, just ask--you'll learn quickly.
If it´s in the global scope it´s better to use:
function foo()
{
alert('foo');
}
var a = 'foo';
window[a]();
than eval(). Because eval() is evaaaaaal.
Exactly like Nosredna said 40 seconds before me that is >.<
Definitely avoid using eval to do something like this, or you will open yourself to XSS (Cross-Site Scripting) vulnerabilities.
For example, if you were to use the eval solutions proposed here, a nefarious user could send a link to their victim that looked like this:
http://yoursite.com/foo.html?func=function(){alert('Im%20In%20Teh%20Codez');}
And their javascript, not yours, would get executed. This code could do something far worse than just pop up an alert of course; it could steal cookies, send requests to your application, etc.
So, make sure you never eval untrusted code that comes in from user input (and anything on the query string id considered user input). You could take user input as a key that will point to your function, but make sure that you don't execute anything if the string given doesn't match a key in your object. For example:
// set up the possible functions:
var myFuncs = {
func1: function () { alert('Function 1'); },
func2: function () { alert('Function 2'); },
func3: function () { alert('Function 3'); },
func4: function () { alert('Function 4'); },
func5: function () { alert('Function 5'); }
};
// execute the one specified in the 'funcToRun' variable:
myFuncs[funcToRun]();
This will fail if the funcToRun variable doesn't point to anything in the myFuncs object, but it won't execute any code.
This is kinda ugly, but its the first thing that popped in my head. This also should allow you to pass in arguments:
eval('var myfunc = ' + variable); myfunc(args, ...);
If you don't need to pass in arguments this might be simpler.
eval(variable + '();');
Standard dry-code warning applies.
So I had an interview where I was asking the purpose of declaring and calling a function immideately, and i couldn't answer it, i.e:
(function(){
// code
})();
What's the reason for doing this?
Object-Oriented JavaScript - Second Edition: One good application of immediate (self-invoking) anonymous functions
is when you want to have some work done without creating extra global
variables. A drawback, of course, is that you cannot execute the same
function twice. This makes immediate functions best suited for one-off
or initialization tasks.
The syntax may look a little scary at first, but all you do is simply
place a function expression inside parentheses followed by another set
of parentheses. The second set says "execute now" and is also the
place to put any arguments that your anonymous function might accept:
(function() {
})();
or
(function() {
}());
are the same:
So I started learning javacript and I've noticed that the coding convention for functions and callbacks is something like this (this is a jQuery example but I've seen these everywhere):
$.getJSON('some/url.json', function(a) {
// do stuff with a here
});
Coming from other languages, I would usually write the above as this:
function myFunction(myVar){
//do stuff with myVar here
};
$.getJSON('some/url.json', myFunction());
Why is the former usually the preferred way of writing in JS, instead of the [probably more readable] latter?
There are plenty of good reasons to use the second, more explicit, format (assuming you fix the issue listed in the comment), including:
reusing the function passed as a callback
giving that function a definitive name to make it easier to debug
making sure that function is noted as something important in your system
separating out that functions because it's simply too long to comfortably declare in place
But the first format, with an anonymous function passed as a callback is short and sweet. If you don't need to reuse the function, if it's relatively short, and if it's not of high importance in your system, it can be really useful to declare it exactly where you use it. You avoid adding another variable to your scope, and you make it entirely clear exactly what that function is for.
It's not the preferred way. You can do anything you want. However, if you need to reuse the function, then you need to do your second option, or alternatively the following, for code reuse:
// in some accessible context/namespace
App.myCallback = function(a){
...
};
// somewhere else
$.getJSON('url', App.myCallback);
Your first example is what is referred to as an anonymous function or block. They are used when they'll only be called once. The second example is when you'd use the function many times... it would be a lot of wasteful typing if you repeated the anonymous block over and over.
I have this function call passed as a string:
var dcall = "tumbsNav(1)";
Is it possible to execute this dynamically like exec in SQL??
exec(dcall)
eval is the equivalent, but you should NOT use it.
Instead, pass the function like this:
var dcall = function() {tumbsNav(1);};
Then call it with:
dcall();
To do this, you want eval(dcall).
eval can open terribly security holes and performance issues in your program. If you need to use it, that usually means you have designed your program poorly.
Instead, you might keep a reference to the function you want to call and hold an array of arguments and use apply, e.g., tumbsNav.apply(null, [1]);. I don't know your code, so that's most general solution I can offer.
Wherever you're storing
var dcall = "tumbsNav(1)";
You can instead store
var dcall = function() {
return tumbsNav(1);
};
Wherever you were calling it, instead of calling
eval(dcall);
You can instead call
dcall();
The only case this wouldn't work is if tumbsNav wasn't defined at the time var func = ... is called. Then you would have to store the string. If the string is completely under your control, then there's no security hole, but be aware of all the problems mentioned by #Porco
As Kolink mentioned, my example would not cause a problem if tumbsNav was not defined when assigning it with a wrapped anonymous function that calls tumbs. The comment above would only make sense if the example had been the following:
var dcall = tumbsNav, darg = 1;
// later in the code, you can call
dcall(darg) ;
Use eval(dcall).
As others have mentioned eval is considered bad practice. The main reasons for this are
1) Improper use can leave your code vulnerable to injection attacks.
2) Maintaining code becomes more difficult (no line numbers, can't use debugging tools)
3) Executes more slowly (browsers can't compile)
4) Scope becomes impossible to predict.
However, if you understand all these then eval can be very helpful.
In my feeble attempt to learn JavaScript, I bought a book which teaches you how to do things in JavaScript, but forgets to mention WHY.
Coming from PHP I am familiar with the typical function syntax:
function name() {return;}
which from what I understand works the same in JS.
Then I decide I want to attempt to use the YUI 3 framework for a small project to continue learning and come across this...YUI Global Object
YUI().use('node', function(Y) {
Y.Node.get('#demo');
});
As far as I understand this is using the 'use' function of the YUI() object, passing 'node' to the 'use' function....but then what...why is it declaring a function within another function call?
Could someone please explain the syntax being used here?
Also a good reference that explains JavaScript general syntax's similar to php.net would also be beneficial.
Thanks for your help.
Its an anonymous function. Its considered a callback.
In PHP 4 and early versions of PHP 5 you might see something like this:
PHP
function callback($var){
...
}
array_filter( $array, "callback" );
In later versions of PHP 5 you can define them as anonymous functions inline.
So, in JavaScript, the old version would look like this:
JavaScript
function use_callback(Y){
Y.Node.get('#demo');
}
YUI().use('node', use_callback);
But by defining an inline anonymous function, you can save the extra clutter and defined function:
YUI().use('node', function(Y) {
Y.Node.get('#demo');
});
Both those functions are equivalent.
In javascript, functions can be passed around as variables. So, here's some other ways that the YUI code could have been written
//original
YUI().use('node', function(Y) {
Y.Node.get('#demo');
});
//more traditional "global function"
function useNode(Y) {
Y.Node.get('#demo');
}
YUI().use('node', useNode);
//local callback function
var myUseNode = function(Y) {
Y.Node.get('#demo');
}
YUI().use('node', myUseNode);
edit As for the second half of your question, you could write what I know about PHP on a postage stamp, so I can't help you there, sorry :-)
This is constructing an anonymous function, and then passing the function itself in as an argument to use. The use method will then call your anonymous function with a value, which in your function will be called Y, which contains the modules that you asked for in the previous arguments to use.
This is essentially equivalent to the following, which passes myFunction in as a callback to YUI().use, except that the anonymous function doesn't have a name:
function myFunction(Y) {
Y.Node.get('#demo');
}
YUI().use('node', myFunction);
This pattern is used because JavaScript doesn't have any kind of explicit notion of namespaces or modules. They can be emulated, however, by using the scope of a function to act as a sort of namespace. In this case, YUI().use will construct an object that has all of the functionality that you request, and pass that object in to the function you provide, so you can use that Y object to call methods that you have imported.
For a good online reference on JavaScript syntax and methods, I like to use the Mozilla Developer Center documentation. In particular, they have good references on JavaScript and the DOM. As it is part of the Mozilla project, they focus on the methods and syntax supported by Gecko (the rendering engine of Firefox), but they usually include compatibility notes to mention what is portable and what is specific to Gecko.
For your question, I would recommend reading the MDC documentation on functions and function scope. Sadly, the MDC doesn't usually come up on top on a Google search; instead, you get W3Schools, which tends to be lower quality and have more ads. I've found it useful to always prefix my searches for anything about JavaScript or the DOM with "mdc" in order to get the MDC documentation; so, for instance, to find that link, I searched for mdc function, and found what I needed.
In JavaScript, functions are objects. In that case, they are passing in an object as the second parameter value (and defining it inline).
YUI().use('node', function(Y) {
Y.Node.get('#demo');
});
is the same as this:
var xxx = function(Y) {
Y.Node.get('#demo');
};
YUI().use('node', xxx);
It is an anonymous function (akin to lambda function) declaration.
YUI().use('node', function(Y) {
Y.Node.get('#demo');
})
In Javascript, functions are 1st class citizens - they are objects like any other; hence, they can be passed as parameter.
What is being shown is what is known as an anonymous function that is being passed as an argument to a function. I don't think PHP has first-class functions like this, so I have no idea how to explain the syntax in terms of that (I also don't do much with PHP, so..)
Here is my example code:
function something_random(a) {
alert("the type of a is ... " + typeof(a));
if (typeof(a) === 'function') {
a();
}
}
Now with this function in mind, you can plug this into Firebug or something similar and run the following code:
something_random(function () {
alert("This is a test.");
});
Something interesting will happen here - you will get two alerts. One should say "the type of a is... function" and the other should say "this is a test." This is because in JavaScript - as well as some other languages - functions are treated just like objects (well, they technically are objects.)
You can throw around functions all day if you like - they are just like numbers, arrays, and so on.
Something interesting can also happen. You can also pass arguments into anonymous functions, which is something that jQuery does quite a bit (except it uses call, but we won't go there.) This is where you get the special things like where you put function(d) {} in a code.
Hope this helps.