我通过示例了解它们。 :)
首先,采用类似 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();
调用链取决于运行时条件。如果为 true,则调用链如下所示:
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 定义指南,使用定义时有效的作用域链执行函数”。
词法作用域是一个非常非常强大的概念。
希望这可以帮助..:)