什么是词汇范围?

有人能给我一个词汇范围的简单介绍吗?

我通过例子了解他们。 🙂

首先,词法范围(也称为静态范围),类似C语法:

void fun() { int x = 5; void fun2() { printf("%d", x); } } 

每个内部层面都可以访问它的外层。

还有另外一种叫做Dynamic Sc​​ope的方法,在第一次执行Lisp时使用了类C语法:

 void fun() { printf("%d", x); } void dummy1() { int x = 5; fun(); } void dummy2() { int x = 10; fun(); } 

在这里, fun可以访问dummy1或者dummy2 x ,或者在其中声明x的任何函数中访问x任何x

 dummy1(); 

将打印5,

 dummy2(); 

将打印10。

第一个被称为静态的,因为它可以在编译时推导出来,第二个被称为dynamic的,因为外部的范围是dynamic的,并且依赖于函数的连锁调用。

我发现静态范围更容易为眼睛。 大多数语言甚至最终甚至是Lisp(可以兼得,对吗?)。 dynamic范围就像将所有variables的引用传递给被调用函数一样。

举一个例子,为什么编译器不能推导出一个函数的外部dynamic范围,请考虑我们的最后一个例子,如果我们写这样的话:

 if(/* some condition */) dummy1(); else dummy2(); 

调用链取决于运行时间条件。 如果这是真的,那么调用链看起来像:

 dummy1 --> fun() 

如果条件错误:

 dummy2 --> fun() 

在这两种情况下的fun的外部范围是呼叫者加上呼叫者的呼叫者等等

只要提到C语言不允许嵌套函数或dynamic范围。

让我们尝试尽可能最短的定义:

词法范围定义了如何在嵌套函数中parsingvariables名称: 即使父函数已经返回,内部函数也包含父函数的作用域

这就是它的全部! 为了帮助我自己理解这意味着什么,我写了一篇关于JavaScript中的函数范围和词汇范围的深入博客文章,可以在这里find。 也许这可以为别人服务。

词汇(AKA静态)范围是指仅根据文本语料库中的位置来确定variables的范围。 variables总是指其顶级环境。 理解dynamic范围是很好的。

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

词汇部分意味着您可以通过阅读源代码来派生范围。

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

dynamic范围定义了可以在被定义之后的任何地方被调用或引用的全局variables。 有时他们被称为全局variables,尽pipe大多数编程语言中的全局variables是词法范围的。 这意味着,它可以通过读取该variables在此上下文中可用的代码来派生。 也许你必须遵循一个使用或包含子句来findinstatiation或者定义,但是代码/编译器知道这个地方的variables。

在dynamic范围设定中,相比之下,您首先在本地函数中search,然后在调用本地函数的函数中search,然后在调用该函数的函数中search,然后search调用堆栈。 “dynamic”指的是变化,因为每次调用给定的函数时,调用堆栈可能会不同,所以函数可能会根据调用的位置而发生不同的variables。 (见这里 )

要查看dynamic范围的有趣示例,请参见此处 。

欲了解更多细节请参阅这里和这里 。

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的dynamic范围是RegisterClass()/ GetClass()函数对。 其用途请参阅此处 。

比方说,RegisterClass([TmyClass])被调用来注册一个特定的类,通过读取代码(在用户调用的button单击方法中调用)无法预测,调用GetClass('TmyClass')的代码将得到结果与否。 对RegisterClass()的调用不一定要在使用GetClass()的单元的词法范围内。

dynamic范围的另一个可能性是Delphi 2009中的匿名方法 (闭包),因为他们知道调用函数的variables。 它没有按照从那里recursion的调用path,因此不是完全dynamic的。

我喜欢来自@Arak等人的全function,语言不可知的答案。 由于这个问题被标记为JavaScript ,所以我想在这个语言中logging一些非常特殊的注释。

在JavaScript中我们的select范围是:

  • 按原样(没有范围调整)
  • lexical var _this = this; function callback(){ console.log(_this); } var _this = this; function callback(){ console.log(_this); }
  • 绑定callback.bind(this)

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

这是一个演示两种方法的例子。 每当你做出关于如何定义callback的决定时,你都要这样做,所以这适用于承诺,事件处理程序等等。

词汇

以下是您可能称之为JavaScript中callback的Lexical Scoping

 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` } //... 

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

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

上面的代码将返回“我只是一个本地”。 它不会回到“我是一个全球”。 因为函数func()计算了在whatismyscope函数的范围之内最初定义的地方。

不pipe它被称为什么(全球范围/从另一个函数内部),都不会受到影响,这就是为什么全球范围内的价值不会被打印出来。

这就是所谓的词法作用域,其中“ 函数是使用定义的作用域链执行的 ” – 根据JavaScript定义指南。

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

希望这可以帮助..:)

词法范围:在函数之外声明的variables是全局variables,在JavaScript程序中随处可见。 在函数中声明的variables具有函数作用域,仅对该函数内出现的代码可见。

IBM将其定义为:

申报适用的计划或分部单位的部分。 在例程中声明的标识符在该例程中以及在所有嵌套例程中是已知的。 如果嵌套例程声明具有相同名称的项目,则外部项目在嵌套例程中不可用。

例1:

 function x() { /* Variable 'a' is only available to function 'x' and function 'y'. In other words the area defined by 'x' is the lexical scope of variable 'a' */ var a = "I am a"; function y() { console.log( a ) } y(); } // outputs 'I am a' x(); 

例2:

 function x() { var a = "I am a"; function y() { /* If a nested routine declares an item with the same name, the outer item is not available in the nested routine. */ var a = 'I am inner a'; console.log( a ) } y(); } // outputs 'I am inner a' x(); 

围绕词法和dynamic作用域的对话中有一个重要部分是缺less的:对作用域variables的生命周期进行简单解释 – 或者可以访问variables。

dynamic范围只是非常松散地对应于我们传统的思维方式的“全局”范围(我之所以提出两者之间的比较是因为它已经被提及 – 我并不特别喜欢链接文章的解释); 我们可能最好不要在全球和dynamic之间进行比较 – 尽pipe据推测,根据链接的文章,“…它可以作为全球范围variables的替代品。”

那么,用简单的英语,这两个范围机制的重要区别是什么?

词汇范围界定在上述答案中已被很好地定义:词汇范围variables在其定义的函数的本地级别是可用的或可访问的。

然而,由于它不是OP的焦点,dynamic范围界定并没有得到很大的关注,而且它所受到的关注意味着它可能需要更多一点(这不是对其他答案的批评,而是一个“哦,那个答案让我们希望有更多的“)。 所以,还有一点点:

dynamic范围意味着在函数调用的生命周期内,或者在函数执行期间,variables可以被更大的程序访问。 真的,维基百科在解释两者之间的差异方面确实做得很好。 为了不混淆,下面是描述dynamic范围的文本:

dynamic作用域(或dynamic作用域),如果一个variables名的作用域是一个特定的函数,那么它的范围就是函数执行的时间段:当函数运行时,variables名存在,并绑定到它的variables,但在函数返回后,variables名不存在。

词法范围意味着一个函数在定义它的上下文中查找variables,而不是在它周围的范围内查找。

看看如何在Lisp中使用词法作用域,如果你想要更多的细节。 Kyle Cronin在Common Lisp的Dynamic和Lexicalvariables中所选的答案比这里的答案要清楚得多。

巧合的是,我只是在一个Lisp类中学到了这一点,而这恰好也适用于JS。

我在Chrome的控制台中运行这个代码。

 // javascript equivalent Lisp var x = 5; //(setf x 5) console.debug(x); //(print x) function print_x(){ //(defun print-x () console.debug(x); // (print x) } //) (function(){ //(let var x = 10; // ((x 10)) console.debug(x); // (print x) print_x(); // (print-x) })(); //) 

输出:

 5 10 5 

总的来说, “词汇范围”是这样的概念:

程序中特定位置的标识符总是指向相同的variables位置 – 其中“always”的意思是“每次执行包含的expression式”

它所指向的variables位置可以通过静态检查该标识符出现的源代码上下文来确定,而不必考虑整个程序的执行stream程。

 function init() { var name = 'Foo'; // `name` is a local variable created by init function displayName() { // `displayName()` is the inner function, a closure alert(name); // use variable declared in the parent function } displayName(); } init(); 

init()创build一个局部variablesname和一个函数displayName()displayName()init()内部定义的内部函数,仅在init()的主体中可用。 displayName()没有自己的局部variables。 但是,由于内部函数可以访问外部函数的variables,因此displayName()可以访问在父函数init()声明的variables名称。

请注意, displayName()中的alert()成功显示名称variables的值,该variables在其父函数中声明。 这是词法作用域的一个例子,它描述了当函数嵌套时parsing器如何parsingvariables名。 词汇“词汇”是指词汇范围使用源代码中声明variables的位置来确定variables可用的位置。 嵌套函数可以访问在其外部范围声明的variables。