1 js编译过程,理解变量提升
包括 引擎、编译器和作用域;
以var a = 2; 为例,
编译器把代码分解为词法单元,把词法分解为一个树结构。
然后当编译器进行代码生成时,
1,对于var a ,编译器询问作用域是否已经有一个同名的变量存放在当前作用域;是则忽略该声明,否则要求作用域在当前作用于的集合中声明一个新的变量,命名为a;
2,接下来编译器为引擎生成运行时需要的代码,这些代码用来处理a=2;引擎运行时首先询问作用域当前作用域是否存在变量a,是则使用它,否则继续查找;如果最终找到了,则赋值给a,如果没有,则抛出异常;
总结:变量的赋值操作:1),编译器在当前作用域声明一个变量(如果之前没有声明过);2),运行时引擎在作用域链里寻找该变量,如果找到了就赋值;
2 LHS和RHS查询,理解变量的声明和使用
引擎查找变量时,有LHS两种RHS查询,虽然RL是左右的缩写,但这里最好理解为查找“赋值操作的目标是谁LHS”“谁是赋值操作源头RHS”;(LHS是赋值操作用的,RHS则是找到它使用它的值);
例:
function foo(a)
foo(2);
引擎:foo>RHS
引擎:执行foo,a>LHS
引擎:console>RHS:
引擎:a>RHS
引擎:a的值传递给log()
那么,为什么要区分RHS和LHS,
因为在变量还没有声明的时候,这两种查询的行为是不同的;
RHS如果没找到,会抛出ReferenceError异常;LHS如果到了全局都没找到,则会创建一个全局变量交给他;这也是之所以函数内部使用未经声明的变量会成为全局变量的原因;
另外,在严格模式下,LHS没找到也会抛出ReferenceError异常;而使用RHS找到一个变量,使用不合理的操作时(比如引用null或者undefined的属性或者对一个非函数类型的值进行函数调用),则会抛出TypeError异常,这说明起码作用域判别成功了但是,操作时非法或者不合理的;