var 和 let 的作用域规则都是一样的,其声明的变量只在其声明的块或子块中可用。
但:
- var 声明的变量的作用域只能是全局或者整个函数块的。
- let 声明的变量的作用域既可以是全局或者整个函数块,也可以是 if、while、switch等用{}
包裹的代码块。
var 允许在同一作用域中重复声明
而 let 不允许在同一作用域中重复声明,否则将抛出异常(Syntax Error)。
当存在全局对象Window时,
var 在全局环境声明变量,会在全局对象里新建一个属性,即可以通过window和this的指向访问;
而 let 在全局环境声明变量,则不会在全局对象里新建一个属性。
var foo = 'global'
let bar = 'global'
//此时this指向window对象
console.log(this.foo) // 输出:global
console.log(this.bar) // 输出:undefined
var声明的作用域下,存在变量提升现象,即变量可以在声明之前调用,并且不会报错。
console.log(a) // undefined (不会报错,但是还未赋值)
var a = 1;
console.log(a) // 1
let声明的作用域下,虽然变量依然在创建执行上下文的时候就被创建,但是在代码未执行到变量声明语句之前,变量不可访问。此不可访问阶段成为“暂存死区”。会报Reference Error
console.log(x); // undefined
var x = 10;
function foo() {
console.log(x); //Reference Error:
//let导致外部var定义的x也不可访问
//如果去掉函数中的let x的定义,则可以打印外部定义的x=10
let x = 20;
x++;
}
foo();
*补充:理解变量提升现象
1、执行上下文:执行上下文有三类:全局执行上下文、函数执行上下文、eval 函数执行上下文
2、将执行上下文看作一个对象:包括变量对象、作用域链、this对象
3、一个执行上下文的生命周期:
而用 var 声明的变量构建变量对象时进行的操作如下:
上述过程就是我们所谓的“变量提升”,这也就能解释为什么变量可以在声明之前使用,因为使用
是在执行阶段,而在此之前的创建阶段就已经将声明的变量添加到了变量对象中,所以执行阶段通过标识符可以在变量对象中查找到,也就不会报错。
参考博客:深入理解JS:var、let、const的异同 - OneForCheng - 博客园 (cnblogs.com)