函数执行-变量提升

115 阅读2分钟

函数执行与变量提升

我们来看这样一段JavaScript代码,思考打印的结果。

   var name = 'zengge'
   var num1 = 1
   var num2 = 2
   var res = num1 + num2
   console.log(name)
   console.log(res)

很简单对吧,大家都知道函数是由上往下执行的,所以console.log的结果就是zengge3。那么再看下面这一段代码:

   console.log(name)
   var name = 'zengge'
   foo()
   function foo(){
     console.log('foo')
   }

可能看到这里有些同学会觉得,哎在定义变量和函数之前打印变量和函数,那不是报错么?嗯有可能,但是凡事不能想当然,我们把它放到控制台打印一下看看结果: image.png
哈哈有些同学看到这是不是有些困惑,不是应该报错吗?怎么会打印undefinedfoo呢?实际上这涉及到了Javascript的变量提升函数提升。在此之前我们先来了解一下JavaScript的代码执行过程中到底发生了什么,同样拿上一幅图来举例:
首先所有的JavaScript的代码的执行都会在一个叫做执行上下文栈(Execution Context Stack,简称ECS)的地方执行,ECS是存在于js引擎内部的 截屏2022-04-19 20.26.26.png
ok开始分析:

  1. 在JavaScript代码执行之前,会在堆内存中创建一个全局对象:Global Object(GO),该对象中里面会包含Date、Array、String、Number、setTimeout、setInterval等等内置类以及函数,还有一个特殊的window对象指向的是它本身,也就是说你可以window.window.window这样无限套娃(虽然这样没啥意义)。截屏2022-04-19 20.34.18.png
  2. 然后就开始执行代码,全局的代码块为了执行会构建一个全局执行上下文 Global Execution Context(GEC),并会创建一个变量对象Vo(Variable Object),此时的Vo就等于Go 截屏2022-04-19 20.45.11.png
    注意此时Go中有foo函数,foo函数指向的是一块内存地址(0xa00),里面是具体的执行代码。执行里面的代码之前,js会再创建一个函数执行上下文FEC(Function Execution Context)压入ECS中,并且也会创建一个Vo,此时的Vo指的是活跃对象Ao(Activation Object),函数中的定义的变量,函数等都会存在这个Ao中,并且作用域链this指向也会在这个里面(之后的章节会讲到)。 截屏2022-04-19 20.56.56.png
    随后函数执行完后,打印出foo,FEC和GEC从ECS中弹出,代码执行完毕。 截屏2022-04-19 21.01.54.png\