HTML:
<script type="text/javascript">
var x = "overriden";
</script>
<script src="myjs.js"></script>
myjs.js:
$(document).ready(function(){
var x = x || "default val";
alert(x); // this alerts "default val" and not "overriden"
});
For some reason, x
is ending up as "default val"
and not "overriden"
, even tho initially I'm setting it to "overriden"
before I even include the script reference to myjs.js.
Any idea as to why this is happening? I'm trying to enable the hosting page to set an override for a variable that's used in an included js file, otherwise use the default val.
Source: Tips4all
What you have after variable declaration hoisting is applied:
ReplyDeletevar x;
x = 5;
$(document).ready(function(){
var x;
x = x || "default";
});
It looks at the closest x and sees it's value is undefined which is a falsy value, so x gets set to "default".
You would be fine if they were in the same scope, because the declarations are always hoisted above assignments so:
var x = 5;
var x = x || "default";
Is actually just
var x;
x = 5;
x = x || "default";
This was suggested which is completely pointless:
$(document).ready(function(){
x = x || "default";
});
It will throw a ReferenceError if x is not defined.
So either do the check in the same scope or do something like:
$(document).ready(function(){
var x = window.x || "default";
});
Invalid property reads don't cause a ReferenceError but just return undefined instead.
The var x in the function passed to $(document).ready() is hiding the global scope x variable.
ReplyDeleteIf you just use x = x || "default val";, then the global variable is clobbered. However, it's really a bad idea to have global variables at all.
You are using the var keyword in both places. Try:
ReplyDeletex = x || "default val";
https://developer.mozilla.org/en/JavaScript/Reference/Statements/var
From the above link:
The scope of a variable declared with var is the enclosing function
or, for variables declared outside a function, the global scope (which
is bound to the global object).
x is not defined in the scope of the document ready function.
ReplyDeletevar x is preparing the variable with the value undefined, so it won't get it from the window scope.
Try var x = x || window.x || "default val"; instead.
Since you have it stated with a var that does not get the globally defined object from the html. Try removing the var and see if you get a different result, or change the variable within the function to a different letter.
ReplyDeleteWhen you use var within a function the scope of that var is only to the function. Since you have defined the x variable twice when you are doing the comparison it is attempting to use the variable from within the function.
If you plan to keep the var statement you will need to change the variable name or how you are calling the global x to window.x. The other option is just to drop the var from the function.
The x created on this line:
ReplyDeletevar x = x || "default val";
...is local to the function it is defined in (i.e. it shadows the global x) .
Removing the preceding var will cause both x names to reference the same global variable, but this is generally a bad idea. From the previously-linked Wikipedia page:
This can lead to confusion, as it may be unclear which variable
subsequent uses of the shadowed variable name refer to.
Because you are again declaring a new var x inside document.ready() which is another scope than global. Try this
ReplyDelete$(document).ready(function(){
x = x || "default val";
alert(x); // this will now alert "overriden"
});
You are declaring var x in your function which creates local storage for x and hides previous values.
ReplyDeleteCall it var y, or do as karim79 suggested.
Your var x in the second one is local to that function, and isn't the same as window.x (which is what you've defined in the former block).
ReplyDeletethe keyword var means that you've just created a local variable. So basically what is happening is that:
ReplyDeleteYou declare (in your first block ) x as "overridden"
Memory:
x -> "overriden"
You set the callback to document.ready
Memory:
x -> "overriden"
(after the document is loaded) 3. you run your anonymous function, initialising x with var
Memory:
x->"overriden"
[IN SCOPE]
anonymous_function.x -> "default_value"
[/SCOPE]
"BUT WAIT", you might say, "the code I wrote is var x= x || "default var" so what should happen is local_x=global_x || "default value ,right?
Unfourtunately Javascript doesn't work like that. In javascript, we have function scope, instead of the more widely used block scope. So when you write:
f=function(){
var x=y || "default value";
var y=3;
alert(x);
}
what'll be interpreted in javascript is :
f=function(){
var x;
var y;
x=y || "default value";
y=3;
alert(x);
}
so running y=10; f(); will give you "default value" on the prompt.
So taking off your var will work to fix your problem here, but just remember in general that all your variable declarations are done "at the beginning" of a function, so scope is immediately changed when entering a function.