有人可以给我一个关于词汇范围的简要介绍吗?
我通过例子理解它们.:)
首先,词典范围(也称为静态范围),采用类C语法:
void fun() { int x = 5; void fun2() { printf("%d", x); } }
每个内在级别都可以访问其外层.
还有另一种方法,称为动态范围,首先实现Lisp,再次使用类似C语法的语法:
void fun() { printf("%d", x); } void dummy1() { int x = 5; fun(); } void dummy2() { int x = 10; fun(); }
在这里fun
既可以访问x
的dummy1
或dummy2
,或x
在调用任何函数fun
与x
在其声明.
dummy1();
将打印5,
dummy2();
将打印10.
第一个称为静态,因为它可以在编译时推断,第二个称为动态,因为外部作用域是动态的,取决于函数的链调用.
我发现静态范围对于眼睛更容易.大多数语言最终都是这样,甚至Lisp(可以做到这两种,对吗?).动态范围就像将所有变量的引用传递给被调用函数.
编译器无法推断出函数外部动态范围的一个例子,考虑我们的最后一个例子,如果我们写这样的东西:
if(/* some condition */) dummy1(); else dummy2();
调用链取决于运行时条件.如果是,则调用链如下所示:
dummy1 --> fun()
如果条件为假:
dummy2 --> fun()
fun
两种情况的外部范围都是调用者加上调用者的调用者等等.
只是提到C语言不允许嵌套函数或动态作用域.
让我们尝试最短的定义:
词法范围定义如何在嵌套函数中解析变量名称:内部函数包含父函数的范围,即使父函数已返回.
这就是它的全部!
var scope = "I am global"; function whatismyscope(){ var scope = "I am just a local"; function func() {return scope;} return func; } whatismyscope()()
上面的代码将返回"我只是一个本地".它不会回归"我是一个全球化的".因为函数func()计算最初定义的位于函数whatismyscope范围内的位置.
它不会受到任何调用(全局范围/来自另一个函数)的困扰,这就是为什么全局范围值我是全局的不会被打印的原因.
这称为词法作用域,其中" 函数使用在定义时生效的作用域链来执行 " - 根据JavaScript定义指南.
词汇范围是一个非常强大的概念.
希望这可以帮助..:)
范围定义了可用的功能,变量等区域.例如,变量的可用性在其上下文中定义,比如函数,文件或对象,它们是在中定义的.我们通常称这些局部变量.
词汇部分意味着您可以从阅读源代码中派生范围.
词法范围也称为静态范围.
动态范围定义了可在定义后从任何位置调用或引用的全局变量.有时它们被称为全局变量,即使大多数programmin语言中的全局变量都是词法范围.这意味着,它可以从读取变量在此上下文中可用的代码中派生而来.也许必须遵循uses或includes子句来查找instatiation或定义,但代码/编译器知道这个地方的变量.
相比之下,在动态范围中,首先在本地函数中搜索,然后在调用本地函数的函数中搜索,然后在调用该函数的函数中搜索,依此类推,调用堆栈."动态"指的是变化,因为每次调用给定函数时调用堆栈都可以不同,因此函数可能会根据调用它的位置命中不同的变量.(见这里)
要查看动态范围的有趣示例,请参见此处.
有关详细信息,请参阅此处和此处.
Delphi/Object Pascal中的一些示例
德尔福有词汇范围.
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('TmyClass')的代码将得到结果与否.对RegisterClass()的调用不必使用GetClass();在单元的词法范围内;
动态范围的另一种可能性是Delphi 2009 中的匿名方法(闭包),因为它们知道其调用函数的变量.它不会递归地跟随调用路径,因此不是完全动态的.
词法(AKA静态)范围是指仅根据其在文本语料库中的位置来确定变量的范围.变量始终指向其顶级环境.与动态范围相关的理解很好.
我喜欢@Arak等人的全功能,语言无关的答案.既然这个问题被标记为JavaScript,我想填写一些非常特定于这种语言的注释.
在javascript中,我们对范围界定的选择是:
原样(没有范围调整)
词法 var _this = this; function callback(){ console.log(_this); }
界 callback.bind(this)
值得注意的是,我认为JavaScript 并没有真正的动态范围..bind
调整this
关键字,这很接近,但在技术上并不相同.
以下是展示这两种方法的示例.每次做出关于如何调整回调范围的决定时都会这样做,因此这适用于promises,事件处理程序等.
以下是Lexical Scoping
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` } //...
据我所知,这些方法在行为上是等同的.
词法作用域:在函数外部声明的变量是全局变量,在JavaScript程序中随处可见.在函数内声明的变量具有函数范围,并且仅对出现在该函数内的代码可见.
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();