船新的闭包和作用域理解

55 阅读2分钟

最近在看控制台的时候,突然发现一个神奇的内部属性[[Scopes]]

image.png

勾起了我对作用域深深回忆:

  1. 每个函数都有自己的作用域作用域中包含了该函数声明的所有顶层变量
  2. 函数可以访问上层作用域,也就是说,当查找变量时,如果执行的函数本身没有这个变量,那就会向上查找,直到全局作用域,这样就形成了作用域链
  3. 作用域静态词法作用域,也就是说在函数声明时就已经确定了

实际上,在早前,查看作用域只能在调试时查看,例如:

let c = 1;
function a() {
  let d = 1
  return ()=> {
     let e = 1;
     console.log(c)
     console.log(d)
     debugger
  }
}

image.png

可以看到这里有四个属性

image.png

先简单的介绍一下这几个属性:

  • Local:就是当前执行函数顶层变量,注意是顶层变量,这里就是e块级作用域的变量实际上是用另一个表示----Block
  • Closure:归类为闭包的变量,也就是a函数中的b
  • Script:全局脚本变量,这里可以看到我们声明的c
  • Global:全局window对象

当然这一定要在调试的时候查看。但是,现在有了更加快捷的方式,就是用[[Scopes]],重新组织刚才的代码:

let c = 1;
function a() {
  let d = 1
  return function f() {
     let e = 1;
     console.log(c)
     console.log(d)
     console.dir(f) // 输出f函数
  }
}

image.png

可以看到几乎输出了一样的输出,只是没有Local,当然为什么没有Local,主要是函数运行,所以只能确定静态词法作用域,所以这里又对应上了静态词法作用域

当然既然看到了Closure,这就不得不提到作用域的一种特殊形式闭包,先来简单回忆一下闭包(Closure)

1.闭包(Closure)就是函数携带其它函数作用域的一种形式

这里有一点要注意,闭包函数函数之间存在的,来一个例子佐证:

function a() {
    {
        let d = 2;
        function b() {
            console.log(d);
            console.dir(b);
            debugger ;
        }
        b()
    }
}

image.png

可以看到函数b引用了上层块级作用域的变量,但是没有闭包(Closure)

所以[[Scopes]]这个内部属性,还是非常有用的,不过目前的御三家火狐是没有的:

image.png

image.png