I have two example pages that are behaving differently and I would like to know why. To me they seem consistent with each other based one what I have gathered about scoping in javascript.
1.html:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">
function demofunction(x, y) {
z=x+y;
}
</script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>4-6.htm</title>
</head>
<body>
<h1>Bad Scoping</h1>
<script type="text/javascript">
//<![CDATA[
demofunction(3, 2);
alert(z);
var z;
alert(z);
//]]>
</script>
<p> </p>
</body>
</html>
In this example, demofunction runs and sets the global variable z to 5. alert runs and since there is no z in scope it grabs the global scope and finds a z which is equal to 5, it alerts that. then a new local variable named z is defined. the second alert can see that local variable, but since it is undefined, it choses the global one and alerts 5 again.
2.html
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bad Scoping</title>
<script type="text/javascript">
//<![CDATA[
first = 6;
document.writeln('<p>first is ' + first + "</p>");
function letsSee() {
alert(first);
var first;
first = 4;
}
letsSee();
document.writeln('<p>but now first is ' + first + "</p>");
//]]>
</script>
</head>
<body>
</body>
</html>
global first gets set to 6. letsSee() runs and the alert (if consistent) should see no local variable named first so it should alert the global variable 6. then a local first is defined, which is then set to 4. letsSee() exists and the last print prints the global first and shows 6 again.
this does NOT happen though. what happens is that it shows 6, alert has undefined, and shows 6. my question is directed to why does it alert undefined rather than 6? if i comment the line inside letsSee for var first;
i then see that it alerts 6 and then display's 4. this makes sense to me. but why does having that var first after the alert make a difference to what the alert call sees as the value? esp when it didn't make a difference in 1.html.
There are two things that are throwing you off
1. your assumption that the
<script>...</script>
block has its own scope like a function has scope. The truth is that all<script>
blocks exist in the same global scope.2. you've also assumed that the
var
declaration occurs in the order in which it appears in the code. The truth is that allvar
s in a given scope are executed at the beginning of that scope. (-edit- just to clarify: the var declaration happens at the beginning of the scope, but any assignment operation remains at its original spot in the code. The value of a variable that has been declared, but not yet had a value assigned isundefined
).So... in your first example,
var z
is actually declaringz
in the global scope, then the call todemofunction()
operates on that globalz
, and both alerts run against the same globalz
.Whereas, in your second example,
first
is initially set in the global scope, then declared again within the function's local scope. In the function, the alert and the assignment both operate on the local variable. Outside the function thewriteln()
s operate on the global variable.I think that is because function declarations are hoisted in JavaScript - i.e. that function runs up the top, where that variable you are trying to access is not defined.
var
andfunction
declarations are hoisted before any code is executed.behaves like
As an easier to understand example, you can call functions before they are declared:
This is because the
function
declaration is looked at first and hoisted, you can call it anywhere regardless of when/where in the code you declare it. The same happens with variables declared usingvar
. The variable itself (the name) is hoisted. Writingvar foo;
anywhere within a given scope will make any higher-scoped variablefoo
unaccessible within that scope.