编译器在编译过程的第二步中生成了代码,引擎执行它时,会通过查找变量 a 来判断它是否已声明过。查找的过程由作用域进行协助,但是引擎执行怎样的查找,会影响最终的查找结果。

引擎查找变量的方式分两种:

  1. LHS:查找变量的引用,需要赋值的时候才使用
  2. RHS:查找变量的值,只需要得到变量的值的时候使用
function foo(a) {
  console.log(a); // RHS--a RHS--console LHS--log(..)中的参数
}
foo(2);// LHS--foo RHS--foo(..)中的参数

在这段代码中,有两次LHS、三次RHS。
第四行中的 foo(..) 函数的调用需要对 foo 进行 RHS 查询,意味着“去找到 foo 的值,并把它给我”。
代码中隐式的 a = 2 操作可能很容易被你忽略掉。为了给 a 参数赋值,需要进行一次 LHS 查询。
这里还有对 a 进行的 RHS 查询并且将得到的值传给了 console.log(..) 。
为了得到 console.log(..) ,还需要进行一次 RHS 查询,得到 console ,然后发现这个对象中有一个叫 log(..) 的方法。
最后还有一个隐式赋值(对 log(..) 的参数赋值),再进行 LHS 查询,得到 log(..) 方法中的参数。

如果 RHS 查询在所有嵌套的作用域中遍寻不到所需的变量,引擎就会抛出 ReferenceError 异常。值得注意的是,ReferenceError 是非常重要的异常类型。

相较之下,当引擎执行 LHS 查询时,如果在顶层(全局作用域)中也无法找到目标变量,全局作用域中就会创建一个具有该名称的变量,并将其返还给引擎,前提是程序运行在非 “严格模式”下。

作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。如果查找的目的是对变量进行赋值,那么就会使用 LHS 查询;如果目的是获取变量的值,就会使用 RHS 查询。