函数编程-Javascript/EMMAScript中函数的作用域是什么

functional programming - What is the scope of a function in Javascript/ECMAScript?

本文关键字:作用域 是什么 函数 -Javascript EMMAScript 函数编程      更新时间:2023-09-26

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

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

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

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

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

此外,为了回答问题的第二部分:函数存在于声明的任何范围中,就像变量一样。

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

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

以下是ECMAScript语言规范:

10.2进入执行上下文

每个函数和构造函数调用进入新的执行上下文,甚至如果函数正在调用自己递归地。每次返回都会退出执行上下文。抛出的异常,如果没有被抓住,也可以退出一个或更多的执行上下文。

控制时输入执行上下文,范围链被创建和初始化,执行变量实例化,并且确定该值。

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

以下是奥的Javascript:最终指南(第5版):

8.8.1词汇范围界定

JavaScript中的函数是词法上的而不是动态确定范围。这意味着它们在它们是定义的,而不是范围从中执行它们。当函数已定义,当前范围链被保存并成为函数的内部状态。…

强烈推荐Douglas Crockford的书:来回答这些问题

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

Javascript,The Good Parts,同样来自奥。

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

function a() { ... }

var a = function() { ... }

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

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

但你不能做:

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

因为无法覆盖window.document对象。

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

Javascript有两个作用域。全局性和功能性。如果使用"var"关键字在函数内部声明一个变量,那么它将是该函数和任何内部函数的本地变量。如果在函数之外声明一个变量,那么它具有全局作用域。

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

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

。。。

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.'
}