0%

词法作用域和动态作用域

作用域是一套规则,用于确定在何处以及如何查找变量。
作用域有两种主要的工作模型。第一种是最为普遍的,被大多数编程语言所接受的词法作用域,也就是静态作用域,Javascript 正式基于这种作用域的。另一种叫做动态作用域,我们这里不作讨论。我们主要来看一下两者的区别。

词法作用域和动态作用域

  • 词法作用域: 无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定,换句话说,函数的作用域是函数在书写时决定的。
  • 动态作用域: 动态作用域并不关心函数是如何声明以及在何处声明,只关心它们从何处调用,换句话说,函数的作用域是在函数被调用时决定的。

看以下代码:

1
2
3
4
5
6
7
8
9
10
var a = 1;
function foo() {
console.log(a);
}
function bar() {
var a = 2;
foo();
}
bar();
// 结果是 ???

假设 Javascript 采用词法作用域,我们看一下执行过程:

执行函数 foo ,在函数 foo 内部查找是否有局部变量 a ,如果没有,根据函数书写的位置,查找上面一层的代码,发现a=1,所以结果为1;

假设Javascript采用动态作用域,我们看一下执行过程:

执行函数foo,在函数foo内部查找是否有局部变量a,如果没有,就从调用函数的作用域,也就是bar内部查找变量a,发现a=2,所以结果为2;

根据我们前面的说明,Javascript是基于词法作用域的,所以结果为1。

思考

《JavaScript权威指南》在讲到词法作用域时,举了如下例子

1
2
3
4
5
6
7
8
9
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f();
}
checkscope();
1
2
3
4
5
6
7
8
9
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
checkscope()();

根据词法作用域的规则,不论何时何地执行函数f(),返回的scope值都是checkscope内部局部变量scope的值,也就是local scope