您永远无法读取尚未声明的变量,这就是您_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 || [];