词汇范围的简要介绍是什么?
当前回答
范围定义了函数、变量等可用的区域。例如,变量的可用性是在其上下文中定义的,比如函数、文件或对象,它们是在中定义的。我们通常称这些局部变量。
词法部分意味着你可以从阅读源代码中获得范围。
词汇范围也称为静态范围。
动态范围定义了全局变量,这些变量在定义后可以从任何地方调用或引用。有时它们被称为全局变量,尽管大多数编程语言中的全局变量都属于词汇范围。这意味着,可以通过读取代码得出变量在此上下文中可用。也许必须遵循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中的匿名方法(闭包),因为它们知道调用函数的变量。它不会递归地遵循调用路径,因此不是完全动态的。
其他回答
这是一个古老的问题,但这是我对它的看法。
词法(静态)范围是指源代码中变量的范围。
在JavaScript这样的语言中,函数可以被传递、附加和重新附加到其他对象,您可能会想到,这个范围将取决于当时调用该函数的人,但事实并非如此。以这种方式更改作用域将是动态作用域,而JavaScript不会这样做,除非可能使用此对象引用。
要说明这一点:
var a=“苹果”;函数doit(){var a=“ardvark”;返回函数(){警报(a);}}var test=doit();测试();
在示例中,变量a是全局定义的,但在doit()函数中隐藏。此函数返回另一个函数,如您所见,该函数依赖于自身范围之外的变量。
如果您运行这个,您会发现使用的值是aardwark,而不是apple,虽然它在test()函数的范围内,但不在原始函数的词法范围内。也就是说,使用的范围是源代码中显示的范围,而不是实际使用函数的范围。
这一事实可能会产生令人讨厌的后果。例如,您可能会决定更容易单独组织函数,然后在时间到来时使用它们,例如在事件处理程序中:
var a=“苹果”,b=“香蕉”;函数init(){var a=“ardvark”,b=“andicoot”;document.querySelector('button#a').onclick=函数(事件){警报(a);}document.querySelector('button#b').onclick=doB;}函数doB(事件){警报(b);}init();<button id=“a”>a</button><button id=“b”>b</button>
此代码示例分别执行其中一项。您可以看到,由于词法作用域,按钮A使用内部变量,而按钮B不使用。您可能最终嵌套的函数比您想要的更多。
顺便说一句,在这两个示例中,您还将注意到,即使包含函数函数已经运行,内部词汇范围内的变量仍然存在。这称为闭包,指的是嵌套函数对外部变量的访问,即使外部函数已经完成。JavaScript需要足够聪明,以确定这些变量是否不再需要,如果不需要,可以垃圾收集它们。
让我们尝试最短的定义:
词法作用域定义了如何在嵌套函数中解析变量名:即使父函数已返回,内部函数也包含父函数的作用域。
这就是它的全部!
词汇范围是指从执行堆栈中的当前位置可见的标识符(例如,变量、函数等)的词汇。
- global execution context
- foo
- bar
- function1 execution context
- foo2
- bar2
- function2 execution context
- foo3
- bar3
foo和bar总是在可用标识符的词典中,因为它们是全局的。
当执行function1时,它可以访问foo2、bar2、foo和bar的词典。
当执行function2时,它可以访问foo3、bar3、foo2、bar2、foo和bar的词典。
全局和/或外部函数无法访问内部函数标识符的原因是,该函数的执行尚未发生,因此,其标识符均未分配给内存。此外,一旦内部上下文执行,它就会从执行堆栈中删除,这意味着它的所有标识符都已被垃圾收集,不再可用。
最后,这就是为什么嵌套的执行上下文总是可以访问它的祖先执行上下文,因此它可以访问更大的标识符词典。
See:
https://tylermcginnis.com/ultimate-guide-to-execution-contexts-hoisting-scopes-and-closures-in-javascript/https://developer.mozilla.org/en-US/docs/Glossary/Identifier
特别感谢@robr3rd帮助简化上述定义。
词法作用域意味着函数从定义它们的作用域解析自由变量,而不是从它们被调用的作用域。
围绕词汇和动态作用域的对话中有一个重要的部分是缺失的:作用域变量的生存期或何时可以访问变量的简单解释。
动态范围界定与“全局”范围界定在我们传统的思考方式中只是非常松散地对应(我之所以将两者进行比较,是因为已经提到了这一点——我并不特别喜欢链接文章的解释);我们最好不要在全局变量和动态变量之间进行比较,尽管根据链接文章的说法,“……[它]作为全局范围变量的替代品很有用。”
那么,用简单的英语来说,这两种范围界定机制之间的重要区别是什么?
在上面的答案中,词汇范围定义得很好:词汇范围变量在定义它的函数的本地级别是可用的,或者是可访问的。
然而,由于它不是OP的重点,动态范围界定并没有得到太多的关注,它得到的关注意味着它可能需要更多的关注(这不是对其他答案的批评,而是“哦,那个答案让我们希望有更多的关注”)。所以,这里还有一点:
动态作用域意味着在函数调用的生命周期内,或在函数执行时,较大的程序可以访问变量。实际上,维基百科在解释两者之间的差异方面做得很好。为了避免混淆,下面是描述动态范围的文本:
…[I]n动态作用域(或动态作用域),如果变量名的作用域是则其范围是函数正在执行:当函数运行时,变量name存在,并绑定到其变量,但在函数之后返回,变量名不存在。
推荐文章
- 如何使用Jest测试对象键和值是否相等?
- 将长模板文字行换行为多行,而无需在字符串中创建新行
- 如何在JavaScript中映射/减少/过滤一个集?
- Bower: ENOGIT Git未安装或不在PATH中
- 添加javascript选项选择
- 在Node.js中克隆对象
- 为什么在JavaScript的Date构造函数中month参数的范围从0到11 ?
- 使用JavaScript更改URL参数并指定默认值
- 在window.setTimeout()发生之前取消/终止
- 如何删除未定义和空值从一个对象使用lodash?
- 检测当用户滚动到底部的div与jQuery
- 在JavaScript中检查字符串包含另一个子字符串的最快方法?
- 检测视口方向,如果方向是纵向显示警告消息通知用户的指示
- ASP。NET MVC 3 Razor:在head标签中包含JavaScript文件
- 禁用从HTML页面中拖动图像