Different behaviour between inline and non-inline JavaScript - javascript

I am trying to build a timer. Please compare the two situations (the first one works, not the second):
inline javascript http://jsfiddle.net/x7xhA/
non-inline javascript http://jsfiddle.net/x7xhA/1/
What is the problem?

This is a commonly encountered problem with users of jsFiddle's 'JavaScript section'. You see, the code that's put into the 'JavaScript section' is wrapped within a function used as a load handler, so in your second example, the real output result is this:
<script type='text/javascript'>
//<![CDATA[
$(window).load(function(){
var seconds = 0;
function timedCount() {
$("#txt").val(seconds);
seconds += 1;
setTimeout("timedCount()",1000);
}
});
//]]>
</script>
Now, timedCount isn't a global function anymore, as it's available in the scope of the load handler only, and when you use setTimeout with a string of code, this gets evaluated from the global scope.
Ways to fix this include:
change the setTimeout call to setTimeout(timedCount, 1000);
What this does, is passes the actual function object to setTimeout. Rather than evaluate the string of code, from global scope, each time, this essentially preserves the ability to call the function as scope doesn't matter anymore - you're handing the function to setTimeout.
var seconds = 0;
function timedCount() {
$("#txt").val(seconds);
seconds += 1;
setTimeout(timedCount,1000);
}
make timedCount a global function using timedCount = function() { ... };
This merely makes timedCount a global, so that when setTimeout tries to evaluate timedCount(); from the global scope, it succeeds as there is a timedCount function in the global scope.
var seconds = 0;
timedCount = function() {
$("#txt").val(seconds);
seconds += 1;
setTimeout("timedCount();",1000);
}

The second one wraps the timedCount function in jQuery ready function, hence is not available in global scope.
Fixed: http://jsfiddle.net/x7xhA/2/

Related

Javascript variable not displaying in simple HTML script

I'm trying to have a simple html page that counts up indefinitely. But for some reason my second variable is not being displayed. The second variable is an embedded javascript timer As you can see the first variable is displayed, but not the second. Apologies, I'm a beginner.
https://dl.dropboxusercontent.com/u/44188718/time.html
<script>
var test;
test = 123;
</script>
<script>document.write(test)</script>
<script>
var time;
time = 0;
function startTimer()
{
window.setTimeout(add(), 60 * 1000);
}
add()
{
var += 1;
}
</script>
<script>document.write(time)</script>
Your middle script element contains several errors.
This line:
window.setTimeout(add(), 60 * 1000);
should be:
window.setInterval(add, 60 * 1000);
setTimeout() calls a function exactly once. setInterval() calls a function repeatedly. Also note that I've removed the () after add - with parentheses it calls the function immediately and passes its result to setTimeout() or setInterval(), but you want to pass the function itself so just use the function name with no parentheses. (And the window. part is optional).
Then this line:
add()
should be:
function add()
And this:
var += 1;
should be:
time += 1;
// OR
test += 1;
(I'm not sure which variable you intend to increment.)
Also you never call the startTimer() function.
Finally, in your add() function you'd need to actually output the value. document.write() is almost never a good idea, so I'd suggest creating an element on your page to hold the number and updating its content:
<div id="timer"></div>
document.getElementById("timer").innerHTML = time; // or = test; (whichever var you want)
Demo of all of the above: http://jsfiddle.net/Y3XMk/
Or the same effect with simplified code: http://jsfiddle.net/Y3XMk/1/
There are several misconsceptions in your code, so I will try to go through them.
You have to specify the function keyword when you define a function. In your case:
add(){ ... }
Should be:
function add() { ... }
Then you can safely call it from your setTimeout code.
Using the keyword var you are basically telling that you are about to define a variable for the current scope. First of all, since the current scope is window anyways (the global scope), you don't need to add var. Secondly, you have to use the variable name when you change it, or add to it. In your case:
var += 1
Should be:
time += 1
Functions get called once, when you call them. In your case, document.write(time) will get called once when the document is parsed, and hence will write 1 in your document. You have to call the write method inside your add function, to have numbers show up at every interval. So:
function add(){
time += 1;
document.write(time);
}
setTimeout calls the specified callback function once, after the time is passed, I believe you are looking for setInterval. You can use it like so:
function startTimer(){
window.setInterval(add, 60 * 1000);
}
But don't forget to call your function, in order for the timer to start.
Here is an example of your code (it works every second instead):
Working fiddle
There are a lot of things wrong with your code.
I believe what you are trying to do is this:
<script>
var time = 0;
window.setInterval(function(){
document.write(time);
time++;
}, 60*1000);
</script>
See a working demo here:
http://jsfiddle.net/8MVFB/
Just click "Run".

When will I need a javascript anonymous function immediately invoked?

I see no situation where I need this
(function(param){
alert(param);
//do something
})("derp");
istead of this
alert("derp");
//do something
EDIT: ok, thanks everybody, i think i got it.
so if you have this:
var param = "x";
var heya = "y";
(function(param){
alert(param);
//do something
})(heya);
the global variable "param" will be ignored in the scope of the anonymous function?
How about this scenario?
Example #1 - Uses an Immediately Invoked Function Expression that closes over a single variable and returns another function. Resulting in a beautiful, encapulated function.
var tick = (function () {
//Example of function expression + closure
var tock = 0;
return function() {
return ++tock;
}
}());
//It is impossible to alter `tock` other than using tick()
tick(); //1
tick(); //2
tick(); //3
tick(); //4
VERSUS
Example #2 - Uses a Function Declaration w/ a global variable
//Unnecssary global (unless wrapped in another function, such as jQuery's ready function)
var tock = 0;
function tick() {
return ++tock;
}
tick(); //1
tock = 4; //tock is exposed... and can be manipulated
tick(); //5
tock = 6;
tick(); //7
It is a contrived example but still a real case scenario in situations where people may want to generate consecutive UNIQUE ID's with no possibility of collision.
Well, you don't - for this simple example.
In JavaScript, variables are scoped to functions; therefore, if you wrap it in a function, you avoid global namespace pollution.
Well, in the example you've given, no, there probably isn't any reason why you would do this.
However, such a pattern is used typically to ensure that variables or functions, you require at a global level
Can be isolated from others potentially defined in other libraries
thus is an effective way to hide private variables
Can be protected against being tampered with by other libraries
Globals in Javascript are evil.
In particular, when working with jQuery I will frequently enclose the $(callback(){}) in a function like this, so that I can have global state for the jQuery code that I don't want inside the callback itself, usually because I have other code that isn't necessarily dependant on the jQuery ready initialisation:
function(){
var something = 'something';
$(function(){
something = 'jQuery bound';
});
}();
Aside from polluting the global namespace, memory usage is the other reason to do this - if you're pulling in a big data structure that only gets used once, wrapping that in a (function(){})() block means that you know it will be cleaned up once the function is finished executing.

Why won't my timer increment the number?

I recently learned javascript. I was experimenting with it. Now, I tried to make a simple timer. Here is the code:
<html>
<head>
<script type="text/javascript">
function start(obj)
{
var t = setTimeout("increment(obj)", 1000);
}
function increment(obj)
{
obj.innerHTML = parseInt(obj.innerHTML) + 1;
start(obj);
}
</script>
</head>
<body>
<p onclick="start(this)">0</p>
</body>
</html>
The contents of the <p></p> should be incremented by 1 every second. Does anyone know why this doesn't work?
Because the string you pass into setTimeout is evaluated at global scope, not the scope within the function, and so doesn't refer to your obj object.
You should never pass strings to setTimeout. Instead, pass it a function reference:
function start(obj)
{
var t = setTimeout(function() {
increment(obj);
}, 1000);
}
function increment(obj)
{
obj.innerHTML = parseInt(obj.innerHTML) + 1;
start(obj);
}
The function we're passing to setTimeout is a closure, which means it has an enduring reference to the items in scope where it's defined. So a second later when the timer mechanism calls it, it still has access to the obj argument of your start function even though the start function has long since returned. More here: Closures are not complicated
The issue (or at least, the first that I see) is that you are passing the string "increment(obj)" to the setTimeout() method, but obj is only defined inside of your start() method. The string that you pass isn't actually evaluated until the timeout triggers, at which point no obj variable is in scope.
There are a few different ways around this. One is to pass a closure to setTimeout() instead of a JavaScript string, like:
function start(obj) {
var nextIncrement = function() {
increment(obj);
};
var t = setTimeout(nextIncrement, 1000);
}
Another (though less preferable) option is to promote obj to the global scope, like:
function start(obj) {
window.obj = obj;
var t = setTimeout("increment(obj)", 1000);
}
In general, however, you should avoid passing a string to setTimeout (and you should also avoid placing things in the global scope unnecessarily). As you have seen, it can cause issues with scope resolution, and for any non-trivial operation it also makes you code much less maintainable. Always prefer passing a function closure when possible.
Also, the following line of code is probably not doing exactly what you expect:
parseInt(obj.innerHTML)
You should always provide the radix argument to parseInt, to avoid errors with values such as 011 (which is 9, rather than 11, because it is evaluated in base-8 due to the leading 0). You can avoid these quirks by simply doing:
parseInt(obj.innerHTML, 10)
...to force a base-10 parse.
Anyways, working example here: http://jsfiddle.net/dSLZG/1
The problem is with this line of code:
var t = setTimeout("increment(obj)", 1000);
obj is an identifier in the functions scope -- it is only accessible within the start function. When you pass a string to setTimeout, it is evaluated in the global scope. This means that the obj variable is not available, so nothing is incremented.
You should pass a function object instead, as this will create a closure and your variable will be accessible:
function start(obj)
{
setTimeout(function() {
increment(obj);
}, 1000);
}
Note that I have removed the unnecessary var t =, because you're not doing anything with the timer identifier.
I've copied your code over to jsFidle and added a working example. See sample code.
The problem in your original version is that your variable obj is not defined in the global context. Whenever you pass strings to setTimeout you'll end up having the string evaluated in the global context (where obj is not a variable).
What you should do instead is never pass a string to setTimeout but a function object. This function object holds references to all variables that are set where the function object was defined.
So, because the function object passed to setTimeout in start2 is defined within start2 it has access to all variables and parameters of start2. Your variable obj is one of those and thus accessible within the function object as soon as it is executed by setTimeout.

Difference between JavaScript function declarations?

Why does calling my JavaScript function throw an error when I call it like this
wysiwyg2();
var wysiwyg2 = function()
{
alert(1);
}
but work when I do this?
wysiwyg2();
function wysiwyg2 ()
{
alert(1);
}
You need to define your function variable first, i.e.
var wysiwyg2 = function()
{
alert(1);
}
wysiwyg2();
For a good explanation of the difference, see Why can I use a function before it’s defined in Javascript?
In the first snippet, you're trying to invoke a variable before the variable is defined.
You'd get the same problem from the following code:
test.toString();
var test = new Date;
In the second snippet, you're declaring the function without assigning it to a variable, and this results in a global declaration that is usable in earlier code.
You can think of your javascript as though it's evaluated in two passes. The first pass builds all the objects and names (and remember: functions are objects), and places them "in scope", so to speak. It's kind of like a compilation step. Then the second pass executes the code.
So your second sample works because the first pass built and "scoped" the function before execution. The first sample does not work because the function object is created as part of a variable assignment, and so it's not in scope yet when you try to call it.
You mention another situation in the comments, where the function call and definition are separated into two script blocks. That doesn't work because the engine completes both steps of one block before moving on to the next, and you tried to call the function in a block that is executed before the block where it's defined. You can call function across script blocks, but not until they are defined.
In the first one, you're declaring a function and assigning it to a variable. Thus you won't be able to call it through that variable until it's actually assigned to it.
In the second, you're declaring a named function. And can call that function from wherever (as long as it's in scope).
When entering a new execution context (which is either a function call or global code), JavaScript first goes through a variable instantiation phase during which all variable declarations and function declarations within the global code or function body are examined and create as properties of the current variable object, which is effectively a collection of all the objects that are in the current scope. In particular, any function declaration such as
function wysiwyg2 ()
{
alert(1);
}
... is fully created during this phase, while any variable declaration such as
var a = 2;
... only leads to the creation of a variable called a with a value of undefined during this phase. This is also true of a variable declaration with an assignment to a function expression, such as
var wysiwyg2 = function()
{
alert(1);
}
Only the variable instantiation takes place at this point. Once this phase is complete the rest of the code (including variable assignment) is executed sequentially.

JavaScript idiom: create a function only to invoke it

I am learning YUI and have occasionally seen this idiom:
<script>
(function x(){ do abcxyz})();
</script>
Why do they create a function just to invoke it?
Why not just write:
<script>
do abcxyz
</script>
For example see here.
They're taking advantage of closures.
A short explanation: Since JS uses function-level scoping, you can do a bunch of actions within a function and have it remain in that scope. This is useful for invoking code that doesn't mess with the global namespace. It also allows one to make private variables - if you declare a variable inside of an anonymous function and execute it immediately, only other code inside of the anonymous function can access that variable.
For example, suppose I want to make a global unique id generator. One might do code like this:
var counter = 0;
var genId = function()
{
counter = counter + 1;
return counter;
}
However, now anyone can mess with counter, and I've now polluted the global namespace with two variables (counter and genId).
Instead, I could use a anonymous function to generate my counter function:
var genId = function()
{
var counter = 0;
var genIdImpl = function()
{
counter = counter + 1;
return counter;
}
return genIdImpl;
}();
Now, I only have one variable in the global namespace, which is advantageous. More importantly, the counter variable is now safe from being modified - it only exists in the anonymous function's scope, and so only the function genIdImpl (which was defined in the same scope) can access it.
It looks like in YUI's example code, they just want to execute code that doesn't pollute the global namespace at all.
They want to avoid namespace collisions, I'd guess. Seems as a good practice in JS.

Categories

Resources