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


当前回答

范围定义了函数、变量等可用的区域。例如,变量的可用性是在其上下文中定义的,比如函数、文件或对象,它们是在中定义的。我们通常称这些局部变量。

词法部分意味着你可以从阅读源代码中获得范围。

词汇范围也称为静态范围。

动态范围定义了全局变量,这些变量在定义后可以从任何地方调用或引用。有时它们被称为全局变量,尽管大多数编程语言中的全局变量都属于词汇范围。这意味着,可以通过读取代码得出变量在此上下文中可用。也许必须遵循uses或includes子句才能找到实例化或定义,但代码/编译器知道此处的变量。

相反,在动态作用域中,首先搜索本地函数,然后搜索调用本地函数的函数,然后在调用该函数的函数中搜索,依此类推,直到调用堆栈。“动态”是指更改,因为每次调用给定函数时,调用堆栈都可能不同,因此函数可能会根据从何处调用而命中不同的变量。(见此处)

要查看动态范围的有趣示例,请参阅此处。

有关详细信息,请参阅此处和此处。

Delphi/Object Pascal中的一些示例

Delphi具有词汇范围。

unit Main;
uses aUnit;  // makes available all variables in interface section of aUnit

interface

  var aGlobal: string; // global in the scope of all units that use Main;
  type 
    TmyClass = class
      strict private aPrivateVar: Integer; // only known by objects of this class type
                                    // lexical: within class definition, 
                                    // reserved word private   
      public aPublicVar: double;    // known to everyboday that has access to a 
                                    // object of this class type
    end;

implementation

  var aLocalGlobal: string; // known to all functions following 
                            // the definition in this unit    

end.

Delphi最接近动态范围的是RegisterClass()/GetClass()函数对。有关其用途,请参见此处。

假设调用RegisterClass([TmyClass])来注册某个类的时间无法通过读取代码来预测(它是在用户调用的按钮单击方法中调用的),调用GetClass('MyClass')的代码将得到结果或不得到结果。对RegisterClass()的调用不必在使用GetClass()单元的词法范围内;

动态范围的另一种可能性是Delphi2009中的匿名方法(闭包),因为它们知道调用函数的变量。它不会递归地遵循调用路径,因此不是完全动态的。

其他回答

本主题与内置绑定函数密切相关,并在ECMAScript 6 Arrow函数中介绍。这真的很烦人,因为对于我们想要使用的每一个新的“类”(实际上是函数)方法,我们都必须绑定它才能访问作用域。

默认情况下,JavaScript不会在函数上设置this的范围(它不会设置this的上下文)。默认情况下,您必须明确说出您想要的上下文。

箭头函数自动获得所谓的词法范围(可以访问包含块中变量的定义)。当使用箭头函数时,它会自动将其绑定到最初定义箭头函数的位置,并且该箭头函数的上下文是其包含块。

通过以下最简单的示例,了解它在实践中的工作原理。

在箭头函数之前(默认情况下没有词法范围):

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const globalScope = programming.getLanguage;
console.log(globalScope()); // Output: undefined

const localScope = programming.getLanguage.bind(programming);
console.log(localScope()); // Output: "JavaScript"

使用箭头函数(默认为词法范围):

const programming = {
  language: "JavaScript",
  getLanguage: function() {
    return this.language;
  }
}

const arrowFunction = () => {
    console.log(programming.getLanguage());
}

arrowFunction(); // Output: "JavaScript"

我喜欢@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`
  }
//...

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

词汇(AKA静态)作用域是指仅基于变量在代码文本语料库中的位置来确定变量的作用域。变量始终引用其顶级环境。了解它与动态范围的关系是很好的。

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

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

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

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

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

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

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

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

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

假设我们有以下代码。

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

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

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