【问题标题】:OO Javascript : Definitive explanation of variable scopeOO Javascript:变量范围的明确解释
【发布时间】:2010-09-11 03:00:36
【问题描述】:

谁能解释一下 JS 中的变量作用域,因为它适用于对象、函数和闭包?

【问题讨论】:

    标签: javascript oop


    【解决方案1】:

    未使用 var 声明的变量在范围内是全局的。 函数引入了作用域,但注意 if 块和其他块不引入作用域。

    我还可以通过谷歌搜索 Javascript 范围看到很多关于此的信息。这真的是我推荐的。 http://www.digital-web.com/articles/scope_in_javascript/

    【讨论】:

      【解决方案2】:

      全局变量

      Javascript 中的每个变量都是对象的命名属性。例如:-

      var x = 1;
      

      x 被添加到全局对象中。全局对象由脚本上下文提供,并且可能已经具有一组属性。例如,在浏览器中,全局对象是 window。与浏览器中的上述行等效的是:-

      window.x = 1;
      

      局部变量

      现在如果我们把它改成:-

      function fn()
      {
          var x = 1;
      }
      

      fn 被调用时,会创建一个名为执行上下文 的新对象,也称为作用域(我可以互换使用这些术语)。 x 作为属性添加到此范围对象。因此,对fn 的每次调用都将获得它自己的范围对象实例,因此它自己的 x 属性实例附加到该范围对象。

      关闭

      现在让我们更进一步:-

      function fnSequence()
      {
          var x = 1;
          return function() { return x++; }
      }
      
      var fn1 = fnSequence();
      var fn2 = fnSequence();
      
      WScript.Echo(fn1())
      WScript.Echo(fn2())
      WScript.Echo(fn1())
      WScript.Echo(fn2())
      WScript.Echo(fn1())
      WScript.Echo(fn1())
      WScript.Echo(fn2())
      WScript.Echo(fn2())
      

      注意:WScript.Echo 替换为您的上下文中写入标准输出的任何内容。

      你应该得到的序列是:-

      1 1 2 2 3 4 3 4

      那么这里发生了什么?我们有fnSequence,它将变量x 初始化为1,并返回一个匿名函数,该函数将返回x 的值,然后将其递增。

      当这个函数第一次被执行时,一个作用域对象被创建并且一个属性x被添加到那个值为1的作用域对象中。同样在同一个执行对象中创建了一个匿名函数。每个函数对象都有一个作用域属性,它指向创建它的执行上下文。这创建了一个我们将在后面讨论的作用域链。对此函数的引用由fnSequence 返回并存储在fn1 中。

      请注意,fn1 现在指向匿名函数,并且匿名函数有一个作用域属性指向一个作用域对象,该对象仍然附加了一个x 属性。这被称为closure,其中执行上下文的内容在为其创建的函数完成执行后仍然可以访问。

      现在分配给fn2 时会发生同样的顺序。 fn2 将指向另一个匿名函数,该函数是在第二次调用 fnSequence 时创建的不同执行上下文中创建的。

      作用域链

      fn1 持有的函数第一次执行时会发生什么?为执行匿名函数创建一个新的执行上下文。可以从标识符x 中找到返回值。检查函数的作用域对象是否有x 属性,但没有找到。这就是 作用域链 的用武之地。在当前执行上下文中找不到 x 时,JavaScript 会获取函数的作用域属性持有的对象并在那里查找 x。因为函数作用域是在fnSequence 的执行中创建的,所以它找到了它,检索它的值并递增它。因此输出 1 并且此范围内的 x 递增到 2。

      现在,当fn2 执行时,它最终会附加到另一个执行上下文,其x 属性仍为1。因此执行fn2 也会导致1。

      如您所见,fn1fn2 各自生成自己独立的数字序列。

      【讨论】:

      • 这个答案真的很不准确。 var x = 1;window.x = 1; 不等效。在第二种情况下,x 是可删除的。首先,它不是。使用术语“属性”而不是“变量”或“属性”是没有帮助的,因为“属性”对于 JavaScript 开发人员来说已经有两种含义,而这两种含义都不是您正在使用的含义。此外,您对执行上下文的描述是错误的:如果您要使用 ECMAScript 规范中的术语,那么您确实需要准确地使用它们。 [继续]
      • fn被调用时,x被创建为变量对象的一个属性,它绑定到执行上下文但和它不是一回事.将术语“范围”与“执行上下文”互换使用也无济于事:同样,它们密切相关,每个执行上下文都有一个范围链,但它们不是一回事。例如,可以使用with 语句或catch 子句由执行上下文中的代码更改作用域链。
      • 对不起,批评:您所说的大致正确,但您使用 ECMAScript 规范中的术语解释不准确。
      • @Tim:我接受你所有的批评。然而,我发现即使是最细微的行为也能清晰的超精细精度只有聪明的身体才能正确吸收。我们其他人只是凡人困惑地看着。我曾多次因为稍微“不精确”而被烧毁,但这些天我不再担心它。一个简单的、99% 的时间都有效且易于掌握的“心智模型”比一个难以理解的复杂的“准确和精确的模型”要好。这就是为什么大多数工程师仍然使用牛顿物理学而不是量子物理学的原因。
      • 很公平。我想我会建议使用其他术语,而不是规范中的术语。写完所有这些,我感到内疚,并找到了我喜欢并赞成的答案:)
      【解决方案3】:

      函数引入范围。您可以在其他函数中声明函数,从而创建嵌套范围。内部作用域可以访问外部作用域,而外部作用域不能访问内部作用域。

      变量被绑定到一个范围,使用 var 关键字。所有变量都隐式绑定到顶级范围。因此,如果您省略 var 关键字,您将隐式引用绑定到顶层的变量。在浏览器中,顶层是 window 对象。请注意,window 是自变量,所以 window == window.window

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-23
        • 1970-01-01
        • 2020-02-07
        • 2012-12-23
        • 2011-05-10
        • 2011-07-07
        相关资源
        最近更新 更多