Andy Fish said:
can anybody put forward a sensible argument javascript's behaviour of
creating a new global variable whenever I assign to a previously undeclared
variable. I can't beleive this is just for the sake of convenience (surely
we learned this much from basic).
Well I don't know the why, ECMA offers some interesting argument with
object-orientation, I'll give some details below - see if this makes
sense, decide whether the "var" keyword is useful, and skip if bored
So, Javascript is object-oriented, and variable instantiation
participates of this logic. To fully understand why you have obtained
the described behavior you need to get familiar with the the Variable
Object (10.1.3) and the Reference Object (8.7).
The "short" version is as follows. When entering a specific execution
context (global code, function code), there is a so-called Variable
Object, which holds references to all variables and functions defined
in the context. To put it another way, declaring a variable using the
"var" keyword adds the variable as a property of this Variable Object.
The Variable object in use depends on the type of code; for function
code, this is the Activation Object (of which "arguments" is a
property); for global code, this is the Global Object, i.e. an object
created before any exuction context is entered, and holding all global
variables and properties (such as Math, Date etc...) - in HTML, the
"window" object refers to this global object (you can also use the
"this" keyword); for Eval Code, it depends on the calling context.
Now, what if you don't use the "var" keyword? The answer is that you
don't really make a variable declaration. Consider the following
statement:
function f() {
a = 3;
}
We have an assignment, so according to ECMA 11.13.1 the following is
executed
1. Evaluate LeftHandSideExpression.
2. Evaluate AssignmentExpression.
3. Call GetValue(Result(2)).
4. Call PutValue(Result(1), Result(3)).
5. Return Result(3).
LeftHandsideExpression is "a", AssignmentExpression is "3". So before
putting the value "3" in "a", "a" is evaluated. This is done as
follows (Identifier Resolution, 10.1.4):
1. Get the next object in the scope chain. If there isn't one, go to
step 5.
2. Call the [[HasProperty]] method of Result(1), passing the
Identifier as the property.
3. If Result(2) is true, return a value of type Reference whose base
object is Result(1) and whose property name is the Identifier.
4. Go to step 1.
5. Return a value of type Reference whose base object is null and
whose property name is the Identifier.
As you can see, step 1 to 4 are iterated until there is no more object
in the scope chain, which could match the propertyName "a". So step 5
is executed, that is, a Reference with a "null" base is provided for
the assignment expression.
A Reference is simply a reference to a property of an object. It
consists in two components, the base object, and the property name; as
you've seen, the result of evaluating an identifier is always a value
of type Reference (either because it's found, or because it's not
found).
When in the assignement expression, JS tries to put a value to the
reference, using:
PutValue (V, W)
1. If Type(V) is not Reference, throw a ReferenceError exception.
2. Call GetBase(V).
3. If Result(2) is null, go to step 6.
4. Call the [[Put]] method of Result(2), passing GetPropertyName(V)
for the property name and W for the value.
5. Return.
6. Call the [[Put]] method for the global object, passing
GetPropertyName(V) for the property name and W for the value.
7. Return.
If you look closely at the algorithm, you'll see the step 2 will
return null, since the Reference "a" doesn't have any object behind.
Therefore, step 6 is executed, and the property is declared directly
on the Global Object - that is, declaring a variable without using the
var keyword will result in the variable being global.
here's my proposal: all "global" (document scope) variables must be declared
by 'var' outside a function block.
That makes sense, but the more you'll program in javascript, the more
you'll use advanced scoping to build your scripts, the less you'll
have global variables (in js you can even run a full script without
one global variable, using an anonymous function expression).
HTH
Yep.