草庐IT

Javascript 全局范围分配

coder 2025-02-18 原文

我了解全局范围和 javascript 变量的问题及其普遍的不受欢迎;而且你到处都能找到它们。以下(在浏览器中)是等效的:

var foo = 3; // foo === 3, window.foo === 3
bazz = 10; // bazz === 10, window.bazz === 10

在全局范围内使用 var 关键字声明变量与在代码中任何地方不使用 var 声明它是一样的:您的变量被分配给根(窗口)对象。

我经常看到的一种技术(例如设置谷歌分析)是这样的:

var _gaq = _gaq || [];

... 我遵循的推理是,如果已声明 _gaq,则使用它,如果未声明,则将其创建为数组。它允许粗心的编码不会覆盖已分配给全局变量 _gaq 的任何值。

我不明白的是为什么这会引发错误:

_gaq = _gaq || [];

它们看起来和我一样:_gaq 应该采用 _gaq 的值或初始化为数组。但它会引发引用错误 - 我的问题是:它们为什么不同?

最佳答案

您永远无法读取 未声明的变量,这就是您尝试使用表达式 _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_gaqAssignmentExpression_gqa || [].

因此,首先对 _qaq 求值,结果为 unresolvable reference ,因为变量 _gaq 没有声明。此评估不会引发错误。

然后 _gqa || [] 被评估。这是一个 LogicalORExpression,在 section 11.11 中有描述。作为 LogicalORExpression ||逻辑与表达式。在这种情况下,左侧的 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 错误,该错误又通过评估赋值的右侧执行,这就是错误所在抛出。

那么,为什么 var _gaq = _gaq || 不会发生这种情况? []; ?

这一行:

var _gaq = _gaq || [];

实际上是

var _gaq;
_gaq = _gaq || [];

因为一个叫做 hoisting [MDN] 的东西.这意味着当 _gaq 被求值时,它不会产生一个不可解析的引用,而是一个值为未定义的引用.

(如果变量 _gaq 已经声明(并且可能有一个值),那么 var _gaq 将没有任何效果。)


如果您想从函数内部全局创建 _gaq,请通过引用 window显式执行此操作:

window._gaq = window._gaq || [];

关于Javascript 全局范围分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15388654/

有关Javascript 全局范围分配的更多相关文章

  1. Ruby Koans about_array_assignment - 非平行与平行分配歧视 - 2

    通过ruby​​koans.com,我在about_array_assignment.rb中遇到了这两段代码你怎么知道第一个是非并行赋值,第二个是一个变量的并行赋值?在我看来,除了命名差异之外,代码几乎完全相同。4deftest_non_parallel_assignment5names=["John","Smith"]6assert_equal["John","Smith"],names7end45deftest_parallel_assignment_with_one_variable46first_name,=["John","Smith"]47assert_equal'John

  2. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

    请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

  3. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  4. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

  5. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  6. ruby - 在 Ruby 中重新分配常量时抛出异常? - 2

    我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案

  7. sql - 查询忽略时间戳日期的时间范围 - 2

    我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时

  8. ruby - 使对象的行为类似于 ruby​​ 中并行分配的数组 - 2

    假设您在Ruby中执行此操作:ar=[1,2]x,y=ar然后,x==1和y==2。是否有一种方法可以在我自己的类中定义,从而产生相同的效果?例如rb=AllYourCode.newx,y=rb到目前为止,对于这样的赋值,我所能做的就是使x==rb和y=nil。Python有这样一个特性:>>>classFoo:...def__iter__(self):...returniter([1,2])...>>>x,y=Foo()>>>x1>>>y2 最佳答案 是的。定义#to_ary。这将使您的对象被视为要分配的数组。irb>o=Obje

  9. Ruby 日期参数超出范围 - 2

    我正在尝试使用在我的代码中是动态的Time.local来安排时间。在每个月的第一天,我传递的值是Time.local(2009,9,-1,0)。在PHP中,这会将时间设置为上个月的最后一天。在ruby​​中,我只是得到“ArgumentError:参数超出范围”。是我用错了方法还是什么?谢谢。 最佳答案 您应该使用DateTime类而不是Time。(您可能需要先require'date'并安装activesupportgem。)它比Time更通用,并且可以用DateTime.civil(2009,9-1,-1,0)做你想做的事。为天

  10. ruby - 在 RSpec 中 stub /模拟全局常量 - 2

    我有一个gem,它有一个根据Rails.env的不同行为的方法:defself.envifdefined?(Rails)Rails.envelsif...现在我想编写一个规范来测试这个代码路径。目前我是这样做的:Kernel.const_set(:Rails,nil)Rails.should_receive(:env).and_return('production')...没关系,只是感觉很丑。另一种方法是在spec_helper中声明:moduleRails;end而且效果也很好。但也许有更好的方法?理想情况下,这应该有效:rails=double('Rails')rails.sho

随机推荐