I understand the issues with global scope and javascript variables and their general undesirability; and that you find them everywhere. The following (in a browser) is equivalent:
var foo = 3; // foo === 3, window.foo === 3
bazz = 10; // bazz === 10, window.bazz === 10
Declaring a variable with the var keyword in the global scope is the same as declaring it without a var anywhere in the code: your variable is assigned to the root (window) object.
One technique I see a lot (e.g. setting up google analytics) is this:
var _gaq = _gaq || [];
... and I follow the reasoning that if _gaq has been declared use that, if not create it as an array. It allows careless coding not to overwrite any values already assigned to the global variable _gaq.
What I don't understand is why this throws an error:
_gaq = _gaq || [];
They look equivalent to me: _gaq should take the value of _gaq or be initialised as an array. But it throws a reference error - my question is: why are they different?
You can never read variables which have not been declared, and that's what you are trying with the expression _gaq || []
in the last case.
In this case
_gaq = _gaq || [];
_qaq
has not been declared before and when the right hand side (_gaq || []
) is evaluated, it throws the error.
Here is step by step explanation of what is going on in this case:
The assignment operator is described in section 11.13.1 of the specification:
The production
AssignmentExpression : LeftHandSideExpression = AssignmentExpression
is evaluated as follows:1. Let
lref
be the result of evaluatingLeftHandSideExpression
.
2. Letrref
be the result of evaluatingAssignmentExpression
.
...
LeftHandSideExpression
is _gaq
, the AssignmentExpression
is _gqa || []
.
So first _qaq
is evaluated, which results in an unresolvable reference, since the variable _gaq
is not declared. This evaluation does not throw an error.
Then _gqa || []
is evaluated. This is a LogicalORExpression
and is described in section 11.11 as LogicalORExpression || LogicalANDExpression
. In this case, LogicalORExpression
, the left hand side, is _gaq
and LogicalANDExpression
, the right hand side, is []
.
The expression is evaluated as follows:
1. Let
lref
be the result of evaluatingLogicalORExpression
.
2. Letlval
beGetValue(lref)
.
...
We already know that lref
will be an unsolvable reference because _gaq
was not declared. So lets have a look what GetValue
is doing (defined in section 8.7.1, V
is the value passed to GetValue
):
1. If
Type(V)
is notReference
, returnV
.
2. Letbase
be the result of callingGetBase(V)
.
3. IfIsUnresolvableReference(V)
, throw aReferenceError
exception.
...
As you can see, a ReferenceError
error is thrown in the third step of this procedure, which in turn gets executed by evaluating the right hand side of the assignment, and this is where the error is thrown.
So, why does this not happen with var _gaq = _gaq || [];
?
This line:
var _gaq = _gaq || [];
is actually
var _gaq;
_gaq = _gaq || [];
because of something called hoisting [MDN]. That means when _gaq
is evaluated, it will not result in an unresolvable reference, but a reference with value undefined
.
(If the variable _gaq
is already declared (and potentially has a value), then var _gaq
won't have any effect.)
If you want to create _gaq
globally from inside a function, do it explicitly by referring to window
:
window._gaq = window._gaq || [];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With