var缺陷以及为什么要引⼊let和const?

作⽤域(scope)

作⽤域是指在程序中定义变量的区域,该位置决定了变量的⽣命周期。

作⽤域就是变量与函数 的可访问范围,即作⽤域控制着变量和函数的可⻅性和⽣命周期。

ES6之前,ES的作⽤域只有两种:全局作⽤域和函数作⽤域,是不⽀持块级作⽤域的

  • 全局作⽤域中的对象在代码中的任何地⽅都能访问,其⽣命周期伴随着⻚⾯的⽣命周期。
  • 函数作⽤域就是在函数内部定义的变量或者函数,并且定义的变量或者函数只能在函数内部被访问。函数 执⾏结束之后,函数内部定义的变量会被销毁。

变量提升带来的问题

function foo(){
for (var i = 0; i < 7; i++) {
}
console.log(i);
}
foo()

因为for循环对于var声明的变量是全局的,所以会一直存在,最后打印出7

letconst可以避免这样的问题


JavaScript是如何⽀持块级作⽤域的

function foo(){
var a = 1
let b = 2
{
let b = 3
var c = 4
let d = 5
console.log(a)
console.log(b)
}
console.log(b)
console.log(c)
console.log(d)
}
foo()

let关键字是如何影响执⾏上下⽂的呢?

第⼀步是编译并创建执⾏上下⽂

当进⼊函数的作⽤域块时,作⽤域块中通过let声明的变量,会被存放在词法环境的⼀个 单独的区域中,这个区域中的变量并不影响作⽤域块外⾯的变量,⽐如在作⽤域外⾯声明了变量b,在该作 ⽤域块内部也声明了变量b,当执⾏到作⽤域内部时,它们都是独⽴的存在。

在词法环境内部,维护了⼀个⼩型栈结构,栈底是函数最外层的变量,进⼊⼀个作⽤域块后,就会把 该作⽤域块内部的变量压到栈顶;

当作⽤域执⾏完成之后,该作⽤域的信息就会从栈顶弹出,这就是词法环 境的结构。

当执⾏到作⽤域块中的console.log(a)这⾏代码时,就需要在词法环境变量环境中查找变 量a的值了

沿着词法环境的栈顶向下查询,如果在词法环境中的某个块中查找到了,就 直接返回给JavaScript引擎,如果没有查找到,那么继续在变量环境中查找。

思考题

let myname= '极客时间'
{
console.log(myname)
let myname= '极客邦'
}

当不在块级作用域声明变量的时候,代码会正常执行

当在块级作用域里面声明的时候,会因为let声明的变量在编译阶段会被加⼊执⾏上下⽂的词法环境,⽽且不会被提升到作⽤域的顶部而报错