一个变量有它的作用域,比如简单的:

  1. ## 全局作用域
  2. let a = 1;
  3. a = a + 1;
  4. println(a);

a 的作用域在 let 定义后,在整个脚本内有效,我们称之为全局作用域,在这个范围内,你可以正常地读写它。

但是你可以限定一个变量的作用域,通过大括号来引入一个嵌套的作用域:

  1. ## examples/scope1.av
  2. let a = 1; ## 全局作用域内的 a
  3. {
  4. ## 嵌套作用域 scope1
  5. let a = 2; ## let 定义了 scope1 内有效的变量 a
  6. println(a); ##打印 scope1 内的 a
  7. a = 3; ##给 scope1 的变量 a 赋值
  8. }
  9. println(a); ## 打印全局作用域的 a

上面的代码将打印:

  1. 2
  2. 1

首先打印嵌套作用域内的定义的 a ,它在里面被赋值为 2,嵌套作用域内的 a “掩盖” 了全局作用域定义的 a 变量,在离开嵌套作用域后,继续打印了全局作用域的变量 a ,它的值仍然是 1。

如果你有其他语言的经验,这个概念还是很好的理解的。这里 scope1 作用域和全局作用域形成了父子关系, scope1 的父作用域是全局作用域,我们通过 let 定义的 a 仅在 scope1 内有效。

let 语句

let 语句就是让你在特定作用域内定义一个变量,如果父作用域有同名的变量,将“掩盖”父作用域的变量。如果不使用 let ,你读写的将仍然是父作用域的变量:

  1. ## examples/scope2.av
  2. let a = 1; ## 全局作用域内的 a
  3. {
  4. ## 嵌套作用域 scope1
  5. a = 2; ## 不适用 let,访问的还是全局作用域的变量 a
  6. println(a); ##打印 scope1 内的 a
  7. a = 3; ##给全局作用域的变量 a 赋值
  8. }
  9. println(a); ## 打印全局作用域的 a

去掉 let 之后,打印结果为:

  1. 2
  2. 3

全局作用域的变量 ascope1 内被修改成了 3。

嵌套作用域

作用域还可以继续深层嵌套,遵循的规则不变:

  1. let 定义当前作用域的变量,这些变量同时可以被它的子作用域访问和修改,离开当前作用域后不可触达。
  2. let 定义的变量将“掩盖”父作用域的同名变量。
  3. 子作用域可以访问和修改父作用域定义的变量,离开子作用域后修改继续生效。

稍微复杂点的例子:

  1. ## examples/scope3.av
  2. ## examples/scope3.av
  3. let a = 1;
  4. {
  5. a = 2;
  6. let a = 3;
  7. b = 4;
  8. {
  9. a = 5;
  10. b = 6;
  11. let c = 7;
  12. println("a in scope2:" + a);
  13. println("b in scope2:" + b);
  14. println("c in scope2:" + c);
  15. }
  16. println("a in scope1:" + a);
  17. println("b in scope1:" + b);
  18. println("c in scope1:" + c);
  19. }
  20. println("a in global scope:" + a);
  21. println("b in global scope:" + b);
  22. println("c in global scope:" + c);

打印出:

  1. a in scope2:5
  2. b in scope2:6
  3. c in scope2:7
  4. a in scope1:5
  5. b in scope1:6
  6. c in scope1:null
  7. a in global scope:2
  8. b in global scope:null
  9. c in global scope:null

可以仔细阅读下这个代码和输出,整个规则还是比较容易理解的。