JavaScript深入理解作用域
作用域分为全局作用域和局部作用域
作用域实现流程:编译、执行、查询、嵌套、异常
编译阶段
JavaScript为解释型语言,边解释边执行
以var a = 1;
为例
1.分词
编译器把程序分解成词法单元
{
"var":"keyword", //关键字
"a":"indentifier", // 标识符
"=":"assignment", // 分配
"1":"interger", // 整形
";":"eos", // end of statement 结束语句
}
2.解析
将词法单元解析成AST(Abstract Snatax Tree)抽象语法树
3.代码生成
将AST转换成机器指令等待执行的过程
执行阶段
1.引擎运行代码时,首先查找当前作用域,看a变量是否在当前作用域下
2.如果在当前作用域下,就使用这个变量,将1赋值给a变量
3.不在则继续查找这个变量,找不到时,引擎抛出异常
查询阶段
查询分为LHS查询(左查询)、RHS查询(右查询)。根据等号区分
function foo(a){
console.log(a);
}
foo(2);
1.foo()对foo进行RHS引用
2.实参2复制值给形参a过程:相当于a=2过程,a执行LHS引用
3.函数内部console.log(a):对console执行RHS引用,找到console并查看是否有log()方法
4.传递值进入console.log()过程:对a进行RHS引用,找到a的值,将其传入console.log();
总结:函数调用,函数需要RHS引用;函数传参,传入一个变量时,变量需要RHS引用获取值;实参传入形参时,相当于形参赋值,形参需要LHS引用。
嵌套阶段
作用域变量查找机制
当前作用域内无法找到变量时,引擎就会在外层嵌套作用域继续查找,直到找到该变量,或者到达全局作用域位置。
当前作用域-》外层嵌套作用域-》。。。-》全局作用域-》内置函数or变量
案例
function foo(a){
function fo(){
console.log(a + b);
}
fo();
}
var b = 2;
foo(4);
变量查找过程
1.查找foo,当前作用域(全局作用域)直接找到,运行foo()
2.查找fo,当前作用域(foo内部作用域)直接找到,运行fo()
3.查找console,当前作用域(fo内部作用域)未找到-》外层嵌套作用域(foo函数作用域)没找到-》全局作用域没找到-》内置函数找到,执行console.log()函数
4.查找a变量,当前作用域(fo内部作用域)没找到-》外层嵌套作用域(foo函数作用域)找到,获取a的值
5.查找b变量,当前作用域(fo内部作用域)没找到-》外层嵌套作用域(foo函数作用域)没找到-》全局作用域找到,获取b的值,执行。
异常
如果在当前所有作用域找不到a变量,则在全局创建这个变量;使用严格模式