词法作用域和块级作用域的介绍

块级作用域

定义: 使用代码块来限定标志的使用范围。
块级作用域的访问范围 : 从变量的声明开始到变量所在的 最近的 花括号( { } ) 结束.
注意:ES5 以前是不支持 块级作用域的, 只支持词法作用域.

词法作用域

定义: 代码在编写过程中出来的作用范围。js执行过程分两个阶段:预解析, 解释执行。
块级作用域的访问范围 : 词法作用域与块级作用域不同, 在 js 中词法作用域的变量在当前作用域中具有全局可访问性.

变量访问规则( 变量搜索原则 )
操作步骤:
1> 将所有的 script 标签看成一个 0 级作用域.可以考虑绘制一条直线.上面标记为 0 级。
2> 在全局作用域中,凡是看到声明, 名字等就在线上标记一个举行块, 里面放置需要的名字( 不要数据的值 )。
3> 0 级链绘制完,分析 0 级作用域中所有的函数,凡是函数, 引出 1 级链,依旧绘制直线。
4> 分别在函数中检查是否有声明, 如果有绘制到对应的链中, 如此往复, 得到新的链, 每一条先都比原来的数字 +1。
5> 绘制完成后, 即得到作用域链结构。

变量搜索原则
凡是需要访问变量, 会考虑在当前作用域中查找是否含有该变量的声明. 如果没有对应的声明, 会到上一级作用域链中。查找是否有对应的声明. 如果有直接使用, 结束查找. 如果没有继续到上一级作用域中. 知道 0 级作用域. 如果还没有就会抛出一个错误, 就是 is not defined.

代码分析
分析步骤:
1> js 代码在预解析的时候会做两件事情, 一个是语法, 另一个是记录声明( 不包括函数内的声明 )。
2> 预解析完成后会从第一行代码开始依次执行 js 代码( 语句 )。
3> 如果进入了函数, 会在函数进入, 执行之前, 对函数内再进行对应的预解析。
4> 如果函数内预解析结束, 再从函数开始的位置一步一步的执行代码。

具体事例分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var num = 123;
function func1() {
num = 456;
function func2() {
var num = 789;
function func3() {
console.log(num);//undefined
var num = 'abc';
}
func3();
console.log(num);//789
}
func2();
console.log(num);//456
}
func1();

  1. 全局的预解析,在script标签中,找到0级作用域,并用直线标明,实例中可以看出,0级上面有变量num和函数func1();在func1()下面画直线并标明1级,找到函数func2();在func2()下面画直线并标明2级,找到变量num,func3();在func3()下面画直线并标明3级,并找到变量num;
  2. 赋值:0级的变量num为123;调用函数func1(),然后将num赋值,由于1级没有变量,直接找到0级的num并将赋值给num = 456,同时打印出num为456;给2级func2()的的num赋值num = 789,并打印num为789;再调用func3()到3级,先打印num的值,由于没有赋值,所以是undefined,然后再赋值num为abc。