作用域是什么
    定义JS引擎如何在当前作用域以及嵌套的子作用域中根据标识符名称进行变量查找
    简称:根据名称查找变量的一套规则
    传统语言的编译:
    1.分词、词法分析
    这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,考虑程序 var a = 2;。这段程序通常会被分解成
    为下面这些词法单元:var、a、=、2 、;
    2.解析/语法分析(Parsing)
    这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法
    结构的树。这个树被称为“抽象语法树”(Abstract Syntax Tree,AST)。
    3.代码生成
    将 AST 转换为可执行代码的过程称被称为代码生成。简单来说就是有某种方法可以将 var a = 2; 的 AST 转化为一组机器指 令,用来创建一个叫作 a 的变量(包括分配内存等),并将一个值储存在 a 中。

    关于var a = 2;所产生的操作
    1.编译器首先会将这段程序分解成词法单元,然后将词法单元解析成一个树结构。
    2.但是当编 译器开始进行代码生成时,
    3.遇到 var a,编译器会询问作用域是否已经有一个该名称的变量存在于同一个作用域的
    集合中。如果是,编译器会忽略该声明,继续进行编译;否则它会要求作用域在当前作
    用域的集合中声明一个新的变量,并命名为 a。
    4.接下来编译器会为引擎生成运行时所需的代码,这些代码被用来处理 a = 2 这个赋值
    操作。引擎运行时会首先询问作用域,在当前的作用域集合中是否存在一个叫作 a 的
    变量。如果是,引擎就会使用这个变量;如果否,引擎会继续查找该变量
    关于编译器LHS和RHS
    如果查找的目的是对 变量进行赋值,那么就会使用 LHS 查询;如果目的是获取变量的值,就会使用 RHS 查询。
    小测验:
    function foo(a) {
    var b = a;
    return a + b;
    }
    var c = foo( 2 );
    1. 找出所有的 LHS 查询(这里有 3 处!)
    c = ..;、a = 2(隐式变量分配)、b = ..
    2. 找出所有的 RHS 查询(这里有 4 处!)
    foo(2..、= a;、a ..、.. b