返回

JavaScript作用域与作用域链:一文读懂词法环境与词法作用域

前端


在编程世界中,作用域是一个非常重要的概念,它决定了变量和函数在程序中的可见性和生命周期。在JavaScript中,作用域主要分为词法作用域(Lexical Scope)和动态作用域(Dynamic Scope)两种。

  • 词法作用域也称为静态作用域,它是在编译时确定变量和函数的作用域。在词法作用域中,变量和函数的作用域是由它们在代码中的位置决定的。

  • 动态作用域是在运行时确定变量和函数的作用域。在动态作用域中,变量和函数的作用域是由它们在调用栈中的位置决定的。

JavaScript使用词法作用域,这意味着变量和函数的作用域是由它们在代码中的位置决定的。

作用域链是将所有活动词法环境连接到一起的链。作用域链在每个执行上下文中都是相同的。

作用域链从当前执行上下文开始,一直向上到全局执行上下文。

当一个变量或函数在当前执行上下文中找不到时,作用域链就会被用来查找该变量或函数。

一、作用域类型
JavaScript中有两种主要的作用域类型:

  1. 全局作用域 :在全局作用域中声明的变量和函数在程序的任何地方都可以访问。

  2. 局部作用域 :在函数中声明的变量和函数只能在该函数内访问。

二、作用域链

作用域链是一个包含所有父作用域的列表,当在某个作用域中访问变量时,JavaScript会首先在该作用域中查找该变量,如果找不到,则会沿着作用域链向上查找,直到找到该变量为止。

例如,在下图中,如果在函数foo()中访问变量x,JavaScript会首先在函数foo()中查找变量x,如果找不到,则会沿着作用域链向上查找,直到找到变量x

全局作用域
  函数foo() {
    局部作用域
      变量x
  }

三、闭包

闭包是指能够访问另一个函数作用域中变量的函数。

闭包通常用于在函数执行后仍然能够访问该函数的作用域中的变量。

例如,在下图中,函数foo()返回一个闭包,该闭包能够访问函数foo()的作用域中的变量x

全局作用域
  函数foo() {
    局部作用域
      变量x
      返回一个闭包
  }

四、词法环境

词法环境是一个包含所有变量和函数的集合。

每个执行上下文都有自己的词法环境。

词法环境中的变量和函数只能在该执行上下文中访问。

五、作用域提升

作用域提升是指变量和函数在声明之前就已经存在于作用域中的现象。

作用域提升发生在编译时。

作用域提升只对变量和函数的声明有影响,对变量和函数的赋值没有影响。

例如,在下图中,变量x在声明之前就已经存在于全局作用域中,因此在全局作用域中访问变量x时,JavaScript会首先在全局作用域中查找变量x,如果找不到,则会沿着作用域链向上查找,直到找到变量x

全局作用域
  变量x
  函数foo() {
    局部作用域
      变量y
  }

六、变量提升

变量提升是指变量在声明之前就已经被赋值的现象。

变量提升发生在运行时。

变量提升只对变量的声明有影响,对变量的赋值没有影响。

例如,在下图中,变量x在声明之前就已经被赋值为1,因此在全局作用域中访问变量x时,JavaScript会首先在全局作用域中查找变量x,如果找不到,则会沿着作用域链向上查找,直到找到变量x

全局作用域
  变量x = 1
  函数foo() {
    局部作用域
      变量y = 2
  }

七、作用域总结

  1. JavaScript中作用域是词法作用域。
  2. 作用域链是一个包含所有父作用域的列表。
  3. 闭包是指能够访问另一个函数作用域中变量的函数。
  4. 词法环境是一个包含所有变量和函数的集合。
  5. 作用域提升是指变量和函数在声明之前就已经存在于作用域中的现象。
  6. 变量提升是指变量在声明之前就已经被赋值的现象。