Javascript全局范围分配
我理解全局范围和javascript变量的问题以及它们的一般不受欢迎性;你到处都能找到它们。以下内容(在浏览器中)是等效的:Javascript全局范围分配,javascript,global-variables,Javascript,Global Variables,我理解全局范围和javascript变量的问题以及它们的一般不受欢迎性;你到处都能找到它们。以下内容(在浏览器中)是等效的: var foo = 3; // foo === 3, window.foo === 3 bazz = 10; // bazz === 10, window.bazz === 10 在全局范围中使用var关键字声明变量与在代码中任何地方不使用var声明变量相同:您的变量被分配给根(窗口)对象 我经常看到的一种技术(例如,设置google analytics)是: 。。。我
var foo = 3; // foo === 3, window.foo === 3
bazz = 10; // bazz === 10, window.bazz === 10
在全局范围中使用var关键字声明变量与在代码中任何地方不使用var声明变量相同:您的变量被分配给根(窗口)对象
我经常看到的一种技术(例如,设置google analytics)是:
。。。我遵循的推理是,如果_gaq已被声明,则使用它,如果不使用它,则将其创建为数组。它允许粗心的编码不会覆盖已分配给全局变量_gaq的任何值
我不明白的是为什么会出现错误:
_gaq = _gaq || [];
它们看起来和我一样:_gaq应该取_gaq的值,或者初始化为数组。但是它抛出了一个引用错误-我的问题是:它们为什么不同?如果
=
右侧的\u gaq
之前没有用var
声明,它将抛出一个引用错误。您试图引用一个不存在的变量。“魔法”只适用于分配给不存在的变量
这就像说
x=y+1
;问题不在于不存在的x
,而在于不存在的y您永远无法读取未声明的变量,这就是您在最后一种情况下尝试使用表达式|gaq|124;[]
在这种情况下
_gaq = _gaq || [];
\u qaq
之前未声明,当计算右侧(\u gaq | |【】
)时,它抛出错误
以下是本案例中发生的情况的逐步说明:
赋值运算符在规范的第1部分中描述:
productionAssignmentExpression:LeftHandSideExpression=AssignmentExpression
的计算如下:
一,。让lref
作为计算LeftHandSideExpression
的结果
2.让rref
作为计算AssignmentExpression
的结果
lefthandideexpression
是\u gaq
,赋值表达式是\u gqa |【】
因此首先计算\u qaq
,这会导致一个,因为变量\u gaq
没有声明。此评估不会引发错误
_gaq = _gaq || [];
然后计算\u gqa | |[]
。这是一个LogicalORExpression
,在中描述为LogicalORExpression | | logicaladexpression
。在这种情况下,LogicalORExpression
左侧为\u gaq
,而logicaladexpression
右侧为[]
表达式的计算如下所示:
一,。让lref
作为计算LogicalORExpression
的结果
2.让lval
beGetValue(lref)
我们已经知道,lref
将是一个无法解决的引用,因为没有声明\u gaq
。因此,让我们看看GetValue
正在做什么(在中定义,V
是传递给GetValue
的值):
一,。如果Type(V)
不是Reference
,则返回V
2.让base
成为调用GetBase(V)
的结果
3.如果isUnsolvableReference(V)
,则抛出ReferenceError
异常。
正如您所看到的,在这个过程的第三步中抛出了一个ReferenceError
错误,然后通过计算赋值的右侧来执行,这就是抛出错误的地方
那么,为什么var _gaq=_gaq | |[]不会发生这种情况呢代码>?
这一行:
var _gaq = _gaq || [];
实际上是
var _gaq;
_gaq = _gaq || [];
因为一种叫做。这意味着当计算\u gaq
时,它将不会导致不可解析的引用,而是导致值未定义的引用
(如果变量\u gaq
已经声明(并且可能有一个值),那么var\u gaq
将不会有任何效果。)
如果要从函数内部全局创建\u gaq
,请参考窗口
:
window._gaq = window._gaq || [];
这将引发错误,因为在当前执行上下文的上下文链中找不到该变量。访问无法解析的变量将导致错误
_gaq = _gaq || [];
另一方面,这将试图解决gac试图将其作为窗口对象的成员查找的问题,而窗口对象是全局上下文“持有者”对象。这种情况的不同之处在于它不会抛出错误,但是窗口将返回undefined,因为在窗口对象中找不到该属性
_gaq = window._gaq || [];
因此,由于全局上下文对象是窗口(当谈到浏览器时),如果定义了_gaq,这两条语句将具有相同的效果。当未定义_gaq时,会注意到差异,使用窗口对象访问它可以具有不出错的优势。这里有一个基本概念,在实践中通常很棘手。变量定义在函数作用域的顶部,而赋值仍然发生在定义变量的位置
_gaq = _gaq || [];
使用这个var\u gaq=\u gaq
变量实际上是在执行赋值的实际代码行之前定义的。这意味着当赋值发生时,变量已经在窗口范围内。如果在_gaq前面没有var,则不会发生提升,因此,当分配运行导致参考错误时,还不存在_gaq
如果您想看到这一点,您可以通过以下方式检查_gaq变量何时添加到窗口对象:
function printIsPropOnWindow(propToCheck)
{
for (prop in window)
{
if (prop == propToCheck)
{
console.warn('YES, prop ' + prop + ' was on the window object');
return;
}
}
console.warn('NO, prop ' + propToCheck + ' was NOT on the window object');
}
try {
var _gaq = function() {
printIsPropOnWindow("_gaq");
return a;
}();
} catch (ex) {
printIsPropOnWindow("_gaq");
}
_gaq = "1";
printIsPropOnWindow("_gaq");
如果您按原样尝试一次,并且在使用var之前尝试一次_gaqre