作用域:
作用域是一套规则,用于确定在何处以及如何查找变量。如果查找的目的是对变量进行赋值,那么就会进行LHS查询,如果说起目的是获取变量的值,就会使用RHS查询。
=操作符和调用函数时传入的参数的操作都会导致关联作用域的赋值操作,也就是说会导致LHS查询
首先需要了解几个javaScript的三个相关的角色
1、引擎
从头到尾负责整个javasript程序的编译及其概念
2、编译器
引擎的好朋友之一,负责语法分析及代码生成的脏活和累活
注:
- 分词/词法分析: 将字符组成的字符串分解成对于编程语言来说有意义的代码块,然后分解出来的代码块叫做词法单元,多个 词法单元就组合成词法单元流(像数组一样)
- 解析/语法分析:将词法单元流转换为一个由元素逐级嵌套所组成的代表了程序语法结构的树。这个树叫做‘抽象语法树AST’
- 代码生成:将抽象语法树AST转换为可执行代码的过程
3、作用域
引擎的另一个好朋友,负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常杨哥 的规则,确定当前执行 的代码对这些标识符的访问权限。
//----------------------------------------------------------------------------------------------------------------------------
下面介绍两个编译器的查询类型 (1、LHS 与 2、RHS)
1、LHS:含义是赋值操作的左侧---------> (赋值操作的目标是谁) 注:这里的赋值操作不能理解为“=“”
2、RHS:含义是赋值操作的右侧--------->(谁是赋值操作的源头)
案例:
1、RHS引用
console.log(a)
这里只是对a的RHS查询,因为这里没有对变量a进行赋值,只是查询到变量a的值,然后传递给console.log(xxx)中
2、LHS引用
a = 2;
这里是对变量a的LHS查询,因为当前我们并不需要知道当前的a的值是什么,而只是为了 =2 这个赋值操作找到一个赋值目标
如下程序中的RHS和LHS的查询
function fn(a) {
console.log(a);
}
fn(2);
第4行代码: fn函数的调用需要对fn进行RHS查询
第4行代码中:还有一个隐式的赋值操作就是 a=2 把2的值赋值给a ,这里进行了LHS查询
第3行代码又是对a的RHS查询
第3行代码又有一个查询,就是对console对象进行RHS查询,检查这个值中是否有一个log()的方法
作用域的嵌套:
当一个块被嵌套到另一个块或者是函数中时,就发生了作用域的嵌套,如下
function fn(a) {
console.log(a + b);
}
var b = 2;
fn(2); // 4
当第六行代码执行的时候,就会导致需要查询变量b的值,也就是说对b进行RHS查询,但是这个操作无法是在函数fn内部完成的,因为b变量不属于fn这个函数的作用域内,所以对b的RHSc查询是在fn的上一级作用域(此时是全局作用域)中完成的
LHS和RHS查询都会在当前执行的作用域中开始,如果没有找到它们所需要的标识符,他们就会想上一级作用域进行查找目标标识符,最后抵达全局作用域,无论有没有找到都会停止查询。
不成功的RHS查询会导致抛出一个ReferenceError异常。(如果说试图对这个变量进行不合理的操作,如对一个不是函数的变量进行调用,那么引擎就会抛出另一个异常TypeError)
不成功的LHS查询会导致自动隐式的创建一个全局变量(非严格模式下),该变量使用LHS引用的目标作为标识符,或者抛出一个ReferenceError异常。(严格模式下)