Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable Not Defined, Sometimes

The following code is presented, in the book Head First jQuery.

function lightning_one(t) {
$("#lightning1").fadeIn(250).fadeOut(250);
setTimeout("lightning_one()", t);
}; // end lightning_one

It gets called with this line.

lightning_one(3000);

The observed behaviour is that the lightning fades in and out once, waits 3 seconds, fades in and out again, and then continues to fade in and out. Firebug shows no javascript errors.

I understand why I see what I see. I thought I would attempt to preserve the 3 second interval, so I changed this:

setTimeout("lightning_one()", t);  // nothing in the brackets

to this:

setTimeout("lightning_one(t)", t);  // t is in the brackets

When I refresh the page, the lightning fades in and out once. Firebug tells me that variable t is undefined.

My question is, if the variable t is not defined after my change, how did the command run without error before I changed it? It still has a variable named t.

More Info

Thank you everyone who wrote comments and answers. For the record, in the "end" folder, the code becomes this:

    lightning_one();

   function lightning_one(){
$("#container #lightning1").fadeIn(250).fadeOut(250);
setTimeout("lightning_one()",4000);
    };

I haven't finished the applicable chapter yet so I don't know if the code change gets suggested later on. As mentioned earlier, this might not be the best book out there. However it's the one I bought and I am learning the fundamentals of jQuery from it.

like image 499
Dan Bracuk Avatar asked Dec 12 '12 00:12

Dan Bracuk


2 Answers

Because the first argument of setTimeout as a string is eval-ed, meaning that it will looking into the outer scope of the function in which t is not defined. The first one is fine because you don't use any variables in the call, but the second is not because t is not defined outside the scope of the function. It is in fact local.

Advice: Don't use eval at all. In fact, you don't need the string argument. Use a function expression:

setTimeout(function() {

    lightning_one(t);

}, t);
like image 80
David G Avatar answered Oct 30 '22 19:10

David G


This will work:

setTimeout(function () { lightning_one(t); }, t); 

I'm pretty sure invoking a function from a String (and letting it get evaluated) is a bad practice that should be avoided.

like image 45
jahroy Avatar answered Oct 30 '22 21:10

jahroy