再说说作用域

javascript的作用域是一个老生常谈的问题了。高程啊,或是各种书籍上都有关于javascript的作用域的阐述。这一次看了,《你不知道的JavaScript》里关于作用域的描述,感觉挺不错的。

编译

JavaScript是脚本语言,解释型语言,很多人可能认为它要跟其他的编译型语言划分界限,毫不相干。但是JavaScript确实是有“编译”的。不过与一众编译型语言不同,JavaScript进行的是预编译,这个编译发生在代码执行前的几微妙。

跟作用域相关的角色

主要有三:

  1. 引擎:从头到尾负责整个JavaScript程序的编译和执行过程。
  2. 编译器:负责语法分析,代码生成。
  3. 作用域:负责收集并维护由所有声明的标识符组成的一系列查询,并实施一套非常严格的规则,确定当前执行代码对这些标识符的访问权限。

看个例子

var a = 2;

大家常常会把这句语句的执行过程想成这样:为一个变量分配内存,并命名为a,然后将2这个值保存进这个变量。
然后,这并不完成正确。
实际情况是比较复杂的。大概的过程如下:

  1. 对于var a,编译器询问作用域是否已经有一个名为a的变量存在于当前作用域中,如果有,这个声明会被忽略。如果没有,就会在当前作用域的集合中声明一个新的变量,命名为a。
  2. 对于a = 2部分,引擎在运行时会询问当前作用域,是否有这个名为a的变量,如果有,引擎使用这个变量。如果没有,向上一级作用域寻找。

声明发生在编译,赋值则是运行时候的事情了。

LHS和RHS

LHS和RHS是引擎对变量的两种查询手段。简单来说,L和R分别代表左侧和右侧。再简单来说,左侧就是指如果要对一个变量进行赋值,那么我们要知道的是是否有这个变量,也就是找到操作的目标,我们不关心它的值。右侧是指我们要取得某个变量的指时。
用个例子说明:

function foo(a){
    var b = a;
    return a + b;
}
var c = foo(2);

LHS查询:

  1. 第2行,var b
  2. 第5行,var c
  3. 第5行,foo(2)里的2,
    RHS查询:
  4. 第2行,第2行,b = a
  5. 第3行, a + b 里的a
  6. 第3行, a + b 里的b
  7. 第5行中对于函数的调用。

作用域嵌套

LHS和RHS查询都会再当前执行作用域中开始,如果有需要(也就是说它们没有找到所需的标识符),就会向上一级作用域继续查询目标标识符。要是一直都找不到就会查询到全局作用域为止。

posted @ 2018-02-02 10:11  xzhx  阅读(108)  评论(0编辑  收藏  举报