JS中的作用域有词法作用域和动态作用域,其中词法作用域规则如下
-
只有函数可以限定作用域
-
函数允许访问函数外部父级作用域的数据
-
变量提升规则
-
就近原则
JS解析和变量提升过程如下
先进行预解析,将代码读取到内存中检查,将所有的声明在进行标记,这个标记过程就是声明提升。
在提升时,var标识符声明的变量会将变量名提升至作用域顶部,但不会将赋值与之对应。
函数声明会将函数名称提升至作用域顶部,var声明之后,并将函数体与该函数名绑定。
提升之后,将进行代码执行过程
词法作用域示意如下
在上面的代码中,1代表全局作用域,其中声明了foo方法(调用时this为全局对象),2代表foo函数体的作用域,其中声明了a参数b变量和bar方法(调用时this为全局对象),3代表bar函数体的作用域,其中声明了c参数。
由于函数能够访问外部的父级作用域,所以bar方法可以打印出a,b,c全部三个变量
就近原则示意如下
var a = 'a';
var b = 'b';
function foo(){
var a = 'aaa';
console.log(a)
console.log(b)
}
foo();
//aaa
//b
上面的代码中,console.log方法在foo函数作用域内,在当前作用域和外部作用域都声明a变量时,根据就近原则a的值为当前作用域内声明的值。
词法作用域在方法或变量在定义阶段确定,在ES6之前JS中没有块级作用域,且方法在被调用时会使用动态作用域,ES6新增了let和const局部变量声明方式来实现块级作用域,箭头函数作为方法为调用时使用词法作用域而不是动态作用域。