Javascript/ECMAScript中函数的作用域是什么?

Javascript/ECMAScript中函数的作用域是什么?,javascript,functional-programming,scope,ecma262,Javascript,Functional Programming,Scope,Ecma262,今天我和一位同事讨论了Javascript中的嵌套函数: function a() { function b() { alert('boo') } var c = 'Bound to local call object.' d = 'Bound to global object.' } 在这个例子中,试验指出b在a的身体之外是无法到达的,就像c一样。但是,在执行a()之后,d是-。在《圣经》中寻找这种行为的确切定义,我没有找到我想要的确切措辞;第13节p.7

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

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

在这个例子中,试验指出b在a的身体之外是无法到达的,就像c一样。但是,在执行a()之后,d是-。在《圣经》中寻找这种行为的确切定义,我没有找到我想要的确切措辞;第13节p.71没有说明的是,由函数声明语句创建的函数对象将绑定到哪个对象。我遗漏了什么吗?

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

function a() { ... }


这是静态作用域。函数中的语句在该函数中起作用

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

另外,回答问题的第二部分:函数存在于它声明的任何作用域中,就像变量一样

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

旁注: ECMA标准可能不是找到Javascript答案的最有用的地方,尽管它当然不是一个坏的资源。请记住,浏览器中的javascript只是该标准的一个实现,因此标准文档将为您提供javascript引擎构建时实现者(主要)遵循的规则。它不能提供有关您所关心的实现的具体信息,即主要浏览器。特别是有几本书将为您提供有关主要浏览器中javascript实现的行为的非常直接的信息。为了说明这一区别,我将在下面介绍ECMAScript规范的摘录和一本关于Javascript的书。我想你会同意这本书给出了一个更直接的答案

以下是ECMAScript语言规范中的内容:

10.2输入执行上下文

每个函数和构造函数调用 输入新的执行上下文,甚至 如果函数正在调用自身 递归地。每回都有一个出口 执行上下文。抛出的异常, 如果未捕获,也可以退出一个或多个 更多执行上下文

何时控制 输入执行上下文,即作用域 链已创建并初始化, 执行变量实例化, 这个值是确定的

范围链的初始化, 变量实例化,以及 该值的确定取决于 输入的代码类型

这是O'Reilly的

8.8.1词汇范围界定

JavaScript中的函数在词汇上是一致的 而不是动态确定范围。这 表示它们在中的作用域中运行 它们是定义的,而不是范围 从中他们被执行。当 函数被定义为当前范围 链被保存并成为的一部分 函数的内部状态。

Douglas Crockford的书强烈推荐涵盖此类问题:

,也来自O'Reilly。

function a() {
   function b() {
      alert('boo')
   }
   var c = 'Bound to local call object.'
   d = 'Bound to global object.'
}
d前面没有var,它是全局的。执行此操作以使d成为私有:

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

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

function a() {
    d = 'Hello World';
}
alert(window.d); // shows 'Hello World'
但你不能这样做:

function a() {
    document = 'something';
}
因为无法覆盖window.document对象


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

Javascript有两个作用域。全球化、功能化。如果使用“var”关键字在函数内声明变量,则该变量将是该函数以及任何内部函数的局部变量。如果在函数外部声明变量,则该变量具有全局作用域

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


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

完全正确——广义上讲,
函数a(){}
相当于
var a=function(){}
(有一些细微的语义差异,但没有太大的意义)。谢谢,但是在ECMAScript标准中,我在哪里可以找到以下断言(或者它是否缺失?)“函数中的语句在该函数中的作用域。”在我的印象中,“var a=function(){}”的语义定义良好,但不是“function a(){…}”语句的语义。ECMAScript标准只会为您提供实现ECMAScript的指导原则,Javascript只是其中的一个家族成员。所以你找不到确切的说法,但还有其他资源可以帮助你。见我上面的补充说明。非常感谢你的详细解释,凯帕罗!我确实从引用的两个源代码中了解到,在函数体中,局部变量绑定到局部执行上下文。然而,嵌套函数语句的语义在这方面没有明确说明。我知道该标准不应该说任何关于实现(其中包括Javascript)的内容,尽管它应该明确所有元素和结构的语义。还感谢您提供指向Douglas Crockford的书的指针——我不知道。是的,这种行为在第。ECMAScript标准的第10.1.9条。
function a() {
    document = 'something';
}