JS的作用域
作用域
- 作用域是指程序中定义变量的区域,该位置决定了变量的生命周期和变量的可访问范围,即作用域控制着变量的可见性和生命周期
JS中的作用域
- 全局作用域
- 函数作用域
函数作用域中定义的变量在外部是不能访问的,同时在函数调用结束后,函数作用域中的变量也会销毁 - 块级作用域
在 ES6 引入 let / const 之后出现的,块级作用域跟函数作用域类似,只不过块级作用域是用 {} 括起来的代码块。JS刚设计的时候,为了图方便,所以按照最简单的方式来设计,通过把作用域内部的变量统一提升是最简单的设计,这也导致了JS中变量提升的缺陷。后面为了解决因为变量提升带来的各种问题,ES6引入了 let/const 来声明变量,从而引入了块级作用域
JS 支持块级作用域的机制
通过一段代码来说明
function foo(){
var a = 1
let b = 2
{
let b = 3
var c = 4
let d = 5
console.log(a) // 1
console.log(b) // 3
}
console.log(b) // 2
console.log(c) // 4
console.log(d) // undifined
}
foo()
一行一行来执行这段代码
- 首先这段代码经过编译,生成全局执行上下文和可执行代码,全局执行上下文如图
- 编译完成后,开始执行 foo() 这一行代码,JS引擎发现这是一个函数调用,因此再次编译产生执行上下文和可执行代码,如图
通过上图不难发现,let声明的变量被JS引擎存放在了词法环境当中 - JS引擎继续往下执行,直到遇到
{}
,这个时候foo函数的执行上下文如图
不难发现,块级作用域中let声明的变量以堆栈的形式存放在词法环境当中 - 当代码块执行结束后,词法环境会直接弹出该代码块中的作用域,从而实现一个真正意义上的块级作用域
暂时性死区(TDZ)
在ES6引入了 let 和 const时,也引入了暂时性死区这一机制,即不能在 let/const 变量初始化之前访问它
ES6 引入暂时性死区,主要是防止变量提升的出现,减少运行时错误,防止在变量声明前就使用这个变量。
var foo;
{
foo = 2; // cannot acess 'foo' before initializtion
let foo;
}