1.什么是作用域
存储和访问或者修改变量,是任何一种编程语言最基本的功能之一,变量存在哪里?程序需要时如何找到它?这些问题需要一套良好的规则来规范,这套规则,就称为作用域。
2.理解作用域
引擎:从头到尾负责整个js程序的编译和执行过程
编译器:引擎的好朋友,负责词法分析以及代码生成等脏活累活。
作用域:引擎的另外一个朋友,负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。
var a=2;的执行过程 1.遇到var a,编译器会询问作用域是否已经有一个该名称的变量存在于同一个作用域的集合中,如果是,编译器会忽略该声明,继续进行编译,否则他会要求作用域在当前作用域的集合中声明一个新的变量,命名为a。 2.编译器会为引擎声称运行时所需的代码,这些代码备用处理a=2这个赋值操作。引擎运行时会首先询问作用域,在当前的作用域集合中是否存在一个叫做a的变量,如果是,引擎会使用这个变量,否则,引擎会继续查找a变量。 3.如果引擎最终找到了a变量,就会将2赋值给它,否则引擎会举手示意抛出一个异常。 所以,变量的赋值操作会执行两个动作,首先编译器会在当前作用域中声明一个变量(如果之前没有声明过),然后再运行时引擎会在作用域中查找这个变量,如果能够找到就会对他赋值。
javascript引擎的两种查找类型,含义是赋值操作的左侧与右侧。
LHS:对哪个赋值就对哪个进行LHS引用,可以理解为赋值操作的目标。
RHS:需要获取哪个变量的值,就对哪个变量的值进行RHS引用,理解为赋值操作的源头。
为什么区分LHS和RHS?
在非严格模式下,如果RHS查询在所有嵌套的作用域中遍寻不到所需的变量,引擎就会抛出ReferenceError的异常。如果LHS查询在所有嵌套的作用域中遍寻不到所需的变量,就会在全局作用域下创建一个具有该名称的变量,将其返还给引擎。
在严格模式下,LHS查询和RHS查询一样,在所有嵌套的作用域中遍寻不到所需的变量,引擎就会抛出ReferenceError的异常。如果RHS查询找到了一个变量,但是尝试对这个变量执行不合理的操作,比如试图对一个非函数类型的值进行函数调用,或者引用null或者undefined类型的值中的属性,那么引擎就会抛出另一种异常TypeError。
3.作用域嵌套
当一个块或者函数嵌套在另外一个块或者函数中时,就发生了作用域嵌套,在当前作用域中无法找到这个变量时,引擎就会在外层嵌套的作用域中继续找,直到找到该变量,或抵达最外层的作用域(全局作用域)为止。
4.总结
作用域是一套规则,用于确定在何处以及如何查找变量,如果查找的目的是对变量赋值,那么就使用LHS查询,如果目的是获取变量的值,就用RHS查询。
function foo(a){ var b=a; return a+b; } var c=foo(2); LHS查询:c=..,a=2,b=.., RHS查询:foo(),=a,a..,--b