词汇范围的简要介绍是什么?


当前回答

在这个问题上,我们可以从另一个角度出发,后退一步,看看范围界定在更大的解释框架(运行程序)中的作用。换句话说,假设您正在为一种语言构建一个解释器(或编译器),并负责计算输出,给定一个程序和一些输入。

解释包括跟踪三件事:

状态-即堆和堆栈上的变量和引用内存位置。对该状态的操作,即程序中的每一行代码给定操作运行的环境,即状态在操作上的投影。

解释器从程序中的第一行代码开始,计算其环境,在该环境中运行该行,并捕获其对程序状态的影响。然后,它遵循程序的控制流执行下一行代码,并重复该过程直到程序结束。

为任何操作计算环境的方式都是通过编程语言定义的一组正式规则。术语“绑定”经常用于描述程序的整体状态到环境中的值的映射。注意,我们所说的“总体状态”不是指全局状态,而是指在执行过程中的任何一点上每个可到达定义的总和)。

这是定义范围问题的框架。现在进入下一部分我们的选择。

作为解释器的实现者,您可以通过使环境尽可能接近程序的状态来简化任务。因此,无论前一行是赋值、函数调用、从函数返回还是控制结构(如while循环),一行代码的环境都将简单地由前一行代码环境定义,并将该操作的效果应用于该行代码。

这就是动态作用域的要点,其中任何代码运行的环境都绑定到由其执行上下文定义的程序状态。

或者,你可以想象一个程序员使用你的语言,简化他或她的跟踪变量取值的任务。关于过去执行的全部结果的推理涉及太多的路径和太多的复杂性。词法作用域通过将当前环境限制在当前块、函数或其他作用域单元及其父级(即包围当前时钟的块或调用当前函数的函数)中定义的状态部分来帮助实现这一点。

换句话说,使用词法作用域,任何代码所看到的环境都绑定到与语言中明确定义的作用域(如块或函数)相关联的状态。

其他回答

var scope = "I am global";
function whatismyscope(){
   var scope = "I am just a local";
   function func() {return scope;}
   return func;
}

whatismyscope()()

上述代码将返回“我只是本地人”。它不会返回“我是一个全球人”。因为函数func()计算最初定义的位置,该位置在函数whatismyscope的范围内。

无论调用什么(全局范围/甚至来自另一个函数),它都不会麻烦,这就是为什么全局范围值“我是全局的”不会被打印出来的原因。

这被称为词法作用域,根据JavaScript定义指南,“函数使用定义时有效的作用域链执行”。

词汇范围是一个非常强大的概念。

词法作用域意味着函数从定义它们的作用域解析自由变量,而不是从它们被调用的作用域。

JavaScript中的词法作用域意味着在函数外部定义的变量可以在变量声明之后定义的另一个函数内部访问。但事实并非相反;在函数内部定义的变量在该函数外部无法访问。

这个概念在JavaScript中的闭包中大量使用。

假设我们有以下代码。

var x = 2;
var add = function() {
    var y = 1;
    return x + y;
};

现在,当您调用add()-->时,这将打印3。

因此,add()函数正在访问在方法函数add之前定义的全局变量x。这是由于JavaScript中的词法作用域而调用的。

我希望这是有帮助的,这里是我对一个稍微更抽象的定义的尝试:

词汇范围:对程序中其他元素的访问或范围(例如函数或变量),取决于其在源代码中的位置。

事实上,我的逻辑只是建立在以下定义之上:

词汇:与语言的单词或词汇有关(特别是与语法或结构分离的单词){在我们的情况下,是编程语言}。

作用域(名词):操作范围{在我们的例子中,范围是:可以访问的内容}。

注意,ALGOL 60规范中最初的1960年词汇范围定义远比我上面的尝试更为简洁:

词汇范围:源代码中应用名称与实体绑定的部分。来源

我喜欢@Arak这样的人提供的功能齐全、语言不可知的答案。由于这个问题被标记为JavaScript,所以我想插入一些与该语言非常相关的注释。

在JavaScript中,我们的作用域选择如下:

按原样(无范围调整)词法var_this=this;函数callback(){console.log(_this);}绑定回调.bind(this)

我认为值得注意的是,JavaScript并没有真正的动态范围。bind调整this关键字,这很接近,但在技术上并不相同。

下面是一个示例,演示了这两种方法。每次决定如何确定回调的范围时,都要这样做,因此这适用于承诺、事件处理程序等。

词汇

以下是JavaScript中回调的词法范围:

var downloadManager = {
  initialize: function() {
    var _this = this; // Set up `_this` for lexical access
    $('.downloadLink').on('click', function () {
      _this.startDownload();
    });
  },
  startDownload: function(){
    this.thinking = true;
    // Request the file from the server and bind more callbacks for when it returns success or failure
  }
  //...
};

跳跃

作用域的另一种方法是使用Function.prototype.bind:

var downloadManager = {
  initialize: function() {
    $('.downloadLink').on('click', function () {
      this.startDownload();
    }.bind(this)); // Create a function object bound to `this`
  }
//...

据我所知,这些方法在行为上是等效的。