ES6是如何同时支持函数和块级作用域的

 · 2 mins read

ES6前ES只有全局和函数作用域,ES6又新增了块级作用域,同时支持函数作用域和块级作用域,ES6是如何实现的呢?

要一步步解开这个问题,首先要明确作用域的概念。

作用域的概念

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

ES6之前,ES只有全局作用域和函数作用域。

全局作用域中的变量在代码的任何地方都可以访问。

函数作用域中的变量只在该函数内部可以被访问到,函数执行结束之后,函数内部的变量也会被销毁。

ES6又通过let和const关键字新增了块级作用域。块级作用域就是一对大括号包裹的代码,像判断语句、循环和函数等都可以看作一个块级作用域。

函数作用域是如何实现的

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();

上面代码当执行到console.log(a);的时候,变量查找过程是这样的:

OK,本文内容就到这里!如有不当之处,欢迎指出,感谢!