lovelmh13 / myBlog

个人博客 记录菜狗的学习之路
6 stars 0 forks source link

全面的执行上下文与调用栈与块级作用域(写于 2021.6.7) #63

Open lovelmh13 opened 3 years ago

lovelmh13 commented 3 years ago

执行上下文和调用栈,涉及块级作用域

当我们需要执行一段代码:

console.log(foo)

var foo = 2
function foo () {
    return 1
}

console.log(foo)

输出:

function foo
2

这里我们跳过变量提升,就直接说这个当函数名和变量名相同的情况。

浏览器执行代码之前,都会进行一个编译的过程。也就是在这个过程中,产生了执行上下文和执行栈,这个我们后面说。

看一下编译的过程,当前代码会被编译为:

var foo = undefined
function foo () { return 1 }

console.log(foo)
foo = 2
console.log(foo)

函数声明的优先级比变量提升的优先级高,所以在 foo 被赋值为 2 之前,打印 foo 会返回 函数,当 foo 被赋值为 2 以后,就会打印出来 2 了。

执行上下文

showName()
console.log(myName)

var myName = '我的名字'
function showName () {
  console.log('你的名字')
}

当执行上面的代码时,浏览器先进行了编译,然后根据执行上下文和可以执行代码来执行出最后的结果: image

执行完 addAll ,再次弹出栈定,只剩全局执行上下文

img

块级作用域与词法环境

在上面的执行上下文中,我们一直往变量环境里添加变量和函数,词法环境里空空如也。想让词法环境里装东西,就得先看一下块级作用域。

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

刚执行 foo 时的执行上下文

image

可以看到 var 声明的变量在「变量环境」中,而 let声明的变量在「词法环境中」,且词法环境是一个栈结构。并且由于 var 没有块级作用域,所以在 {} 里的 c 也在编译阶段就出现在了 foo 的执行上线文中。

然后执行到 {} 代码块里时

image

代码块里的 b d 入词法环境栈,此时变量环境的 a 已经被置为 1,且块外的 b也被置为了 2。块内的变量并不会影响到块外的同名变量的值。

再继续执行,当执行到 console.log(a) 的时候,会从词法环境开始找起,自顶向下,如果找到了就返回它对应的值,如果没有到找,就再去变量环境里去找:

img

当作用域块执行完以后,属于作用域块内部定义的变量就会从词法环境弹出:

img

参考

极客时间 -> 浏览器与工作原理 -> 浏览器中的JavaScript执行机制