什么是词法作用域的简要介绍?
什么是词法作用域的简要介绍?
词法作用域:在函数外部声明的变量是全局变量,可以在 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();
词法作用域指的是当前执行栈中可见的标识符(例如,变量、函数等)的词汇表。
- 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
的词汇表。
全局和/或外部函数无法访问内部函数的标识符,因为该函数尚未执行,因此其任何标识符都尚未分配到内存。而且,一旦该内部上下文执行完毕,就会从执行堆栈中删除它,这意味着其中所有的标识符已被清除并不再可用。
最后,这就是为什么嵌套执行上下文始终可以访问其祖先执行上下文,因此它可以访问更大的标识符词汇表的原因。
参见:
特别感谢@robr3rd协助简化上述定义。
虽然这是一个古老的问题,但以下是我的看法。
词法(静态)作用域是指一个变量在源代码中的范围。
在像JavaScript这样的语言中,函数可以传递并附加到各种对象上,并且可能会重新附加到其他对象上,您可能认为作用域取决于调用函数的人,但事实并非如此。以这种方式改变作用域将得到动态作用域,并且JavaScript不会这样做,除非使用this
对象引用。
为了说明这一点:
var a='apple';
function doit() {
var a='aardvark';
return function() {
alert(a);
}
}
var test=doit();
test();
a
被全局定义,但在doit()
函数中被遮蔽。该函数返回另一个函数,并且依赖于其自身作用域之外的a
变量。aardvark
,而不是apple
,尽管后者在test()
函数的作用域内,但它不在原始函数的词法范围内。也就是说,使用的范围是在源代码中出现的范围,而不是实际使用函数的范围。var a='apple',b='banana';
function init() {
var a='aardvark',b='bandicoot';
document.querySelector('button#a').onclick=function(event) {
alert(a);
}
document.querySelector('button#b').onclick=doB;
}
function doB(event) {
alert(b);
}
init();
<button id="a">A</button>
<button id="b">B</button>
这个代码示例包含了两种情况。我们可以看到由于词法作用域,按钮A
使用内部变量,而按钮B
则不使用。您可能会发现自己需要嵌套更多的函数。
另外,无论在哪个示例中,都会注意到内部词法范围的变量仍然存在,即使包含函数已经执行完毕。这被称为闭包,指的是嵌套函数对外部变量的访问,即使外部函数已经完成。JavaScript需要足够聪明地确定是否不再需要这些变量,如果不需要,则可以进行垃圾回收。
作用域是变量/绑定可访问的上下文环境。词法作用域意味着局限于封闭的词法代码块中,而不是全局作用域。
为了理解词法环境,让我们先了解作用域的概念:
作用域:
每当你在JavaScript中创建一个函数时,你就创建了一个作用域,这意味着该方法内部的变量将无法从外部访问。在JavaScript中可以有多个作用域。首先是全局作用域。然后假设你定义了一个名为foo
的函数,那么你就创建了由foo
创建的作用域,现在你在foo
内部定义了另一个名为bar
的方法,那么你就在foo
的作用域内创建了另一个由bar
创建的作用域。
function foo(){
let name="foo"
function bar(){
console.log(name)
}
return bar
}
现在,当我们在bar
内部引用变量name
时,JavaScript将无法在bar
中找到任何内容,因此JavaScript将查找其外部作用域foo
并找到该变量,然后使用它。这些作用域的链条称为作用域链。
因此,词法环境基本上为您提供了这个作用域链和一组规则,以便使用它来解析标识符。总体而言,这被称为函数的词法环境,并在运行时用于解析标识符。
请记住,JavaScript在编译阶段定义了这个作用域,因此被称为静态作用域。
词法作用域意味着函数解析自由变量的范围是它们被定义的作用域,而不是它们被调用的作用域。