Skip to content

9.作用域及作用域链

作用域

简单来说,作用域就是变量起作用的范围和区域。作用域的目的是隔离变量,保证不同作用域下同名变量不会冲突。

JS中有三种作用域

  • 全局作用域
  • 函数作用域
  • 块作用域

全局作用域

  • 最外层变量及函数

    js
      var num = 10
      function f1() {
        var num2 = 20
        function f2() {
          console.log(num2)
        }
        console.log(num)
      }
    
      console.log(num)
      f1()
      console.log(num2) // not defined
      console.log(f2) // not defined

    num变量和f1函数在任何地方都可以访问到,反之,不在当前作用域下的变量只能载当前作用域下使用。

  • 不使用var声明的变量

    js
      function f1() {
        num = 10
        var num2 = 20
      }
      f1()
      console.log(num) // global
      console.log(num2) // num2 is not defined

    不使用var声明的变量会进行变量提升(提到全局作用域下),所以num变量在任何作用域下都可以访问到。有时候,我们将不使用var声明的变量称为隐式全局变量

  • window对象所有属性和函数

window对象代表整个浏览器窗口,window对象具有双重角色

  • JS访问浏览器的接口

    window对象下的所有属性和函数都拥有全局作用域。例如setTimeoutalert

  • ECMAScript中规定的global对象

    在全局作用域中使用var所创建的变量都会作为window对象的属性保存;全局作用域中所有的函数都会作为window对象的方法保存

函数作用域

在函数内部定义的变量,拥有函数作用域

js
  var name = '小明'

  function sayHi() {
    var str = 'hello world'
    console.log(str)
  }

  function showName(myName) {
    // 形参也是局部变量
    console.log(myName)
  }


  sayHi() // 'hello world'
  showName(name) // '小明'

  console.log(str) // not defined
  console.log(myName) // not defined

strmyName都是函数内部定义的变量(形参也算函数内部定义的变量),他们的作用域仅限于函数内部,全局作用域中不会访问到。

函数调用时创建,结束后销毁。每调用一次产生一个新的作用域,之间相互独立。

块作用域

使用let或const声明的变量,如果被一个大括号括住,那么这个大括号括住的变量就形成了块级作用域。

js
{
  let a = 10
  console.log(a)
}
console.log(a) // 报错

块级作用中定义的变量只在当前块中生效

作用域链

只要是代码,就至少拥有一个作用域

js
  var num = 10
  function fn() {
    var num = 20
    function fun() {
      console.log(num)
    }
  }
  fn()

上述代码有三个作用域:全局作用域、fn函数作用域、fun函数作用域

作用域链关系如下:

试图在fun函数里访问变量num时:

fun函数作用域内无此变量 -> 上级作用域(fn函数作用域)有此变量,打印

我们把作用域层层嵌套,形成的关系叫做作用域链,作用域链也就是查找变量的过程。

查找变量的过程:当前作用域 --> 上一级作用域 --> 上一级作用域 .... --> 直到找到全局作用域 --> 还没有(报错)

作用域模型

作用域模型分两种

词法作用域

词法作用域是作用域的成因,也称静态作用域。代码在书写时就已经确定作用域了。

js
  var num = 10;
  function f1(){
    console.log(num)
  }
  function f2(){
    var num  = 20;
    f1()
  }
  f2();

根据词法作用域流程如下:f2函数调用 --> f1函数调用 --> 在f1作用域中寻找局部变量num --> 没找到,根据书写位置到上级作用域(全局作用域)查找 --> 发现num,打印10

KESHAOYE-知识星球