执行上下文和作用域

153 阅读3分钟

首先言简意赅对于两个词进行说明

作用域:读写变量的一套规则,即变量生效作用范围,其中js常规情况下遵循词法作用域,即声明时所在位置决定其作用范围。eval with暂不考虑 极其不建议使用

执行上下文:当前代码执行所在环境,其中分为全局环境和函数环境。

在《你不知道的JavaScript》上册这本书中特别表明了js这门语言为及时编译语言,我们在js一执行时便进入全局上下文并进行了预编译进行代码变量的提升分配内存以及相关作用域链的确认。如下图

image.png

举个🌰

没有例子很难理解 所以我们来看下列🌰

  const k = 123

  function a(){
    console.log(k)
  }

  function b(){
    const k = 456
    a()
  }

  b() // 123

我们将上面例子一步步进行拆解

1-1 首先我们要了解一个知识点即上下文执行栈,在js执行时 会首先置入全局上下文 例如下图中右侧CallStack 由于在全局环境中我们由于使用了const声明变量 从而导致产生script作用域(普通函数中使用const或let时不会生成新的作用域 而是直接置于当前作用域中)

image.png 1-2 此时我们看下图可以发现 当前还暂未进行a,b函数的执行 但我们的函数a已经完成作用域链的设置 优先上层是script作用域 其次是全局作用域 也深刻说明了在声明创建这个函数的时候,这个函数的作用域就已经决定了,而是不是在调用的时候

image.png

1-3 当b函数执行时 如下图会向执行上下文栈中置入b函数执行环境 并可以看到当前作用域为自身函数作用域及父级作用域(注:在未执行时不会产生自身函数作用域)

image.png 1-4 向下执行a函数 如下图 可以看到此时调用栈置入a函数执行环境 作用域loacl进行了替换且与b函数无任何相关联 重要的事情也再次验证强调了两次 函数的作用域在声明时就已经决定了,而不是在调用的时候 因此当k寻找不到时 会向上父级作用域进行查找 在script作用域中 找到了为123的k~

image.png

1-5 当a函数执行完毕后将会进行出栈 此时可以看到出栈后local 作用域链变回原b函数置入时所产生的作用域链

image.png

1-6 最后b函数出栈及全局函数依次出栈完成整个js调用

总结补充

最后我们对于上述最开始的解释做一个补充,作用域的产生一定是在产生执行上下文时会进行创建,并对于函数对象所关联的作用域是其在当前上下文中声明时便已经确认的。(不考虑拙劣的eval和with)