13

今天我和一位同事讨论了 Javascript 中的嵌套函数:

function a() {
   function b() {
      alert('boo')
   }
   var c = 'Bound to local call object.'
   d = 'Bound to global object.'
}

在这个例子中,试验指出 b 在 a 的主体之外是不可到达的,就像 c 一样。但是,d 是 - 在执行 a() 之后。在ECMAScript v.3 标准中寻找这种行为的确切定义,我没有找到我正在寻找的确切措辞;Sec.13 p.71没有说的是,函数声明语句创建的函数对象要绑定到哪个对象。我错过了什么吗?

4

5 回答 5

22

这是静态范围。函数中的语句在该函数范围内。

然而,Javascript 有一个古怪的行为,那就是没有var关键字,你就隐含了一个全局变量。这就是你在测试中看到的。您的“d”变量是可用的,因为它是一个隐含的全局变量,尽管它是写在函数体中的。

另外,回答你问题的第二部分:一个函数存在于它声明的任何范围内,就像一个变量一样。

旁注: 您可能不想要全局变量,尤其是不隐含的变量。建议您始终使用 var 关键字,以防止混淆并保持一切清洁。

旁注: ECMA 标准可能不是找到有关 Javascript 答案的最有用的地方,尽管它肯定不是一个糟糕的资源。请记住,浏览器中的 javascript 只是该标准的实现,因此标准文档将为您提供在构建 javascript 引擎时(主要)由实现者遵循的规则。它无法提供有关您关心的实现的具体信息,即主要浏览器。特别是有几本书,它们将为您提供有关主要浏览器中的 javascript 实现如何表现的非常直接的信息。为了说明差异,我将在下面包含 ECMAScript 规范和一本关于 Javascript 的书的摘录。我觉得你'

这是来自ECMAScript 语言规范

10.2进入执行上下文

每个函数和构造函数调用都会进入一个新的执行上下文,即使一个函数正在递归调用自身。每个返回都退出一个执行上下文。抛出的异常,如果没有被捕获,也可能退出一个或多个执行上下文。

当控制进入执行上下文时,作用域链被创建和初始化,变量实例化被执行,并且 this 值被确定。

作用域链的初始化、变量实例化和 this 值的确定取决于输入的代码类型。

这是来自O'Reilly 的Javascript:权威指南(第 5 版)

8.8.1 词法作用域

JavaScript 中的函数是词法而不是动态范围的。这意味着它们在定义它们的范围内运行,而不是在执行它们的范围内运行。定义函数时,当前作用域链被保存并成为函数内部状态的一部分。...

强烈推荐道格拉斯·克罗克福德(Douglas Crockford)的书来解决这些问题:

JavaScript,好的部分 http://oreilly.com/catalog/covers/9780596517748_cat.gif

Javascript,The Good Parts,也来自 O'Reilly。

于 2008-10-24T21:54:18.327 回答
4

据我了解,就范围界定而言,这些是等效的:

function a() { ... }

var a = function() { ... }
于 2008-10-24T21:53:03.273 回答
2

值得注意的是,虽然 d 被创建为“全局”,但实际上它是作为窗口对象的属性创建的。这意味着您可能会无意中覆盖窗口对象上已经存在的内容,或者您​​的变量实际上可能根本无法创建。所以:

function a() {
    d = 'Hello World';
}
alert(window.d); // shows 'Hello World'

但你不能这样做:

function a() {
    document = 'something';
}

因为你不能覆盖 window.document 对象。

出于所有实际目的,您可以想象您的所有代码都在一个巨大的with(window)块中运行。

于 2008-10-24T23:02:19.203 回答
1

Javascript 有两个作用域。全球性和功能性。如果您使用“var”关键字在函数内声明变量,它将是该函数和任何内部函数的本地变量。如果您在函数之外声明变量,则它具有全局范围。

最后,如果你在第一次声明变量时省略了 var 关键字,javascript 会假定你想要一个全局变量,无论你在哪里声明它

因此,您正在调用函数 a,而函数 a 正在声明一个全局变量 d。

于 2008-10-24T23:39:25.230 回答
0

...

function a() {
   function b() {
      alert('boo')
   }
   var c = 'Bound to local call object.'
   d = 'Bound to global object.'
}

前面没有var, d 是全局的。这样做使 d 私有:

function a() {
   function b() {
      alert('boo')
   }
   var c = 'Bound to local call object.'
   var d = 'Bound to local object.'
}
于 2008-10-24T21:56:57.090 回答