1. 作用域是指在程序中定义变量的区域,该位置决定了变量的生命周期。通俗地理解,作用域就是变量与函数的可访问范围,即作用域控制着变量和函数的可见性和生命周期。

1 在 ES6 之前,ES 的作用域只有两种:

  1. 1 全局作用域中的对象在代码中的任何地方都能访问,其生命周期伴随着页面的生命周期。<br />2 函数作用域就是在函数内部定义的变量或者函数,并且定义的变量或者函数只能在函数内部被访问。函数执行结束之后,函数内部定义的变量会被销毁。

其他语言一般都支持块级作用域, ES却没有,同时又因为j变量提升,很容易出现其他问题:

1.1 变量容易在不被察觉的情况下被覆盖掉

  1. var myname = "极客时间"
  2. function showName(){
  3. console.log(myname);
  4. if(0){
  5. var myname = "极客邦"
  6. }
  7. console.log(myname
  8. }
  9. showName()
  10. // undefied
  11. // undefied

image.png

  1. // 另一个变量提升例子
  2. function varTest() {
  3. var x = 1;
  4. if (true) {
  5. var x = 2; // 同样的变量!
  6. console.log(x); // 2
  7. }
  8. console.log(x); // 2
  9. }

image.png

1.2 本应销毁的变量没有被销毁

  1. function foo(){
  2. for (var i = 0; i < 7; i++) {
  3. }
  4. console.log(i);
  5. }
  6. foo()

像变量i这些用在循环遍历的临时变量,执行完遍历后还会保留下来,这会污染变量环境。

2 ES6块级作用域

2.1 块级作用域

就是使用一对大括号包裹的一段代码,比如函数、判断语句、循环语句,甚至单独的一个{}都可以被看作是一个块级作用域。

  1. //if块
  2. if(1){}
  3. //while块
  4. while(1){}
  5. //函数块
  6. function foo(){}
  7. //for循环块
  8. for(let i = 0; i<100; i++){}
  9. //单独一个块
  10. {}

2.2 ES6 引入了 let 和 const 关键字,从而使 JavaScript 也能像其他语言一样拥有了块级作用域。

  1. function letTest() {
  2. let x = 1;
  3. if (true) {
  4. let x = 2; // 不同的变量
  5. console.log(x); // 2
  6. }
  7. console.log(x); // 1
  8. }

2.3 JavaScript 是如何支持块级作用域的

JavaScript 引擎是通过变量环境实现函数级作用域的, 如何实现对块级作用域的支持

  1. function foo(){
  2. var a = 1
  3. let b = 2
  4. {
  5. let b = 3
  6. var c = 4
  7. let d = 5
  8. console.log(a)
  9. console.log(b)
  10. }
  11. console.log(b)
  12. console.log(c)
  13. console.log(d)
  14. }
  15. foo()

在同一段代码中,ES6 是如何做到既要支持变量提升的特性,又要支持块级作用域的

2.3.1

image.png

2.3.2

image.png
注意: 词法环境也是一个栈结构

2.3.3

image.png

2.3.4

image.png

2.4 总结

块级作用域就是通过词法环境的栈结构来实现的,而变量提升是通过变量环境来实现,通过这两者的结合,JavaScript 引擎也就同时支持了变量提升和块级作用域了。

3 let/const不存在变量提升

image.png

4 暂时性死区

只要块级作用域存在let/const命令,则它声明的变量就被绑定binding在这个区域,也就是这个区块对这些变量一开始就形成封闭作用域,不再受外部印象(参考ES6深入浅出)
只要在声明之前使用变量,就会报错。
image.png

  1. let myname= '极客时间'
  2. {
  3. console.log(myname)
  4. let myname= '极客邦'
  5. }

image.png
这个ES6明确规定,跟上面词法环境分析存在相违背,词法分析,执行进入到块级作用域,就会把let、cosnt声明的变量压人词法栈中,已经在内存中了,那为啥使用不了??
image.png
image.png
image.png