您永远无法读取尚未声明的变量,这就是您_gaq || []在最后一种情况下尝试使用的表达式。
在这种情况下
_gaq = _gaq || [];
_qaq_gaq || []之前没有声明过,当评估右侧 ( ) 时,它会抛出错误。
以下是对这种情况下发生的事情的逐步解释:
赋值运算符在规范的第 11.13.1 节中描述:
生产AssignmentExpression : LeftHandSideExpression = AssignmentExpression评估如下:
1. 让lref是评估的结果LeftHandSideExpression。
2. 让rref是评估的结果AssignmentExpression。
...
LeftHandSideExpression是_gaq,AssignmentExpression是_gqa || []。
所以 first_qaq被评估,这导致一个不可解析的引用,因为变量_gaq没有被声明。此评估不会引发错误。
然后_gqa || []进行评估。这是 aLogicalORExpression并且在第 11.11 节中描述为LogicalORExpression || LogicalANDExpression。在这种情况下,LogicalORExpression,左侧,是_gaq并且LogicalANDExpression,右侧,是[]。
表达式计算如下:
1. 让lref是评估的结果LogicalORExpression。
2.lval让GetValue(lref)。
...
我们已经知道这lref将是一个无法解决的引用,因为_gaq没有声明。所以让我们看看GetValue在做什么(在第 8.7.1 节中定义,V是传递给的值GetValue):
1.如果Type(V)不是Reference,返回V。
2. 让base成为调用的结果GetBase(V)。
3. 如果IsUnresolvableReference(V),则抛出ReferenceError异常。
...
如您所见,ReferenceError在此过程的第三步中引发了错误,该错误又通过评估赋值的右侧来执行,这就是引发错误的地方。
那么,为什么这不会发生var _gaq = _gaq || [];呢?
这一行:
var _gaq = _gaq || [];
实际上是
var _gaq;
_gaq = _gaq || [];
因为一个叫做提升[MDN]的东西。这意味着当_gaq被评估时,它不会导致无法解析的引用,而是带有 value 的引用undefined。
(如果变量_gaq已经声明(并且可能具有值),则var _gaq不会产生任何影响。)
如果您想_gaq从函数内部全局创建,请通过引用显式window执行:
window._gaq = window._gaq || [];