作用域
若要转载,请著名出处。
编程语言最基本的功能就是存储变量中的值,并可以对其进行修改。
为了能够存储变量,并找到它们,就需要一套严密的规则,这套规则其实
就是作用域。
让我们先了解一下编译原理
javaScript(文章以后都简称js),其实是一门编译语言。毋庸置疑。
编译的大致过程如下:
1. 分词/词法分析(Tokenizing/Lexing)
可以理解成拆分,把代码块拆分成约定好的词块。
比如: var a = 2 ; ,分词大致会分为var 、a 、=、2、;。
2. 解析/语法分析(Parsing)
分词之后的流(数组)在这一过程被构造成抽象语法树(AST)。
AST的各个节点描述了该拆分代码的信息
3. 代码生成
这一过程就是将AST转换成可执行的代码的过程。
这里只是简单的将编译过程做了阐述,实际过程远远复杂甚之。
理解作用域
作用域
负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套严密的规则,确定当前执行的代码对这些标识符的访问权限。
var a = 2 ;
我们再看看这个简单的列子,简单的分为声明和赋值两个模块解析:
1. 声明 编译器会在作用域中寻找是否有这个声明存在,没有,作用域就会再当前的作用域集合中声明一个变量,并命名为a,有,则继续编译。
2. 赋值 编译器生成赋值代码,引擎执行这段代码的时候会在作用域中寻找是否有a这个变量,有,直接用它,没有,继续寻找。
引擎如何查找变量?
这里简单的介绍两种查找方法
1. LHS
可以简单理解就是赋值操作左侧的变量,虽然不准确,概念上最好理解为找到赋值操作的目标是谁?
2. RHS
可以简单理解就是赋值操作右侧的变量,谁是赋值操作的源头?
为了便于理解我们给个小demo:
function foo(a){
console.log(a); //2
}
foo(2);
这里foo(…) 是RHS查询
隐式的将2赋值给a是LHS
console.log(…)是RHS
作用域嵌套
当一个模块或函数和另一个模块或函数发生重叠嵌套的时候,作用域也嵌套,此时引擎的查找顺序则是从当前作用域开始,逐渐向外层拓展,直到最外层的全局作用域,此时无论找到与否,查找都会停止。
区分两种异常
1. ReferenceError 作用域判别失败
2. TypeError 作用域是判别对了,但是对结果的操作是不合法的。