Вы никогда не можете читать переменные, которые не были объявлены, и это то, что вы пытаетесь сделать с выражением _gaq || []
в последнем случае.
В этом случае
_gaq = _gaq || [];
_qaq
не был объявлен до и, когда правая часть (_gaq || []
) вычисляется, он выдает ошибку.
Вот шаг за шагом объяснение того, что происходит в этом случае:
Оператор присваивания описана в section 11.13.1 спецификации:
The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression
is evaluated as follows:
1. Let lref
be the result of evaluating LeftHandSideExpression
.
2. Let rref
be the result of evaluating AssignmentExpression
.
...
LeftHandSideExpression
является _gaq
, то AssignmentExpression
является _gqa || []
.
Итак, сначала оценивается _qaq
, что приводит к unresolvable reference, так как переменная _gaq
не объявлена. Эта оценка не ошибка.
Затем оценивается _gqa || []
. Это LogicalORExpression
и описан в section 11.11 как LogicalORExpression || LogicalANDExpression
.В данном случае LogicalORExpression
, с левой стороны, находится на _gaq
и LogicalANDExpression
, с правой стороны, находится на []
.
Выражение вычисляется следующим образом:
1. Let lref
be the result of evaluating LogicalORExpression
.
2. Let lval
be GetValue(lref)
.
...
Мы уже знаем, что lref
будет неразрешимой ссылка, потому что _gaq
не был объявлен. Так что давайте посмотрим, что GetValue
делает (определенный в section 8.7.1, V
это значение передается GetValue
):
1. If Type(V)
is not Reference
, return V
.
2. Let base
be the result of calling GetBase(V)
.
3. If IsUnresolvableReference(V)
, throw a ReferenceError
exception.
...
Как вы можете видеть, ошибка ReferenceError
брошен в третьем шаге этой процедуры, которые в turn получает исполнение, оценивая правую часть задания, и здесь возникает ошибка.
Итак, почему это не происходит с var _gaq = _gaq || [];
?
Эта линия:
var _gaq = _gaq || [];
фактически
var _gaq;
_gaq = _gaq || [];
из-за чего-то под названием hoisting [MDN]. Это означает, что когда оценивается _gaq
, оно будет не результат неразрешимой ссылкой, но ссылка со значением undefined
.
(Если переменная _gaq
уже объявлена (и, возможно, имеет значение), то var _gaq
не будет иметь никакого эффекта.)
Если вы хотите создать _gaq
глобально внутри функции, сделать он явно со ссылкой на window
:
window._gaq = window._gaq || [];
Они не совсем эквивалентны, они отличаются поведением, когда вы пытаетесь ['delete'] (http://perfectionkills.com/understanding-delete/) их. – Bergi
Лучшее объяснение «необъявленных назначений» и почему они отличаются от глобальных назначений ('foo = 0'! =' Var foo = 0' в глобальной области), я могу найти ** [в этом блоге] (http : //perfectionkills.com/understanding-delete/) **, который помог мне понять внутреннюю разницу. –