浏览器中JS大概的执行流程

  • 编译阶段
  • 执行阶段


初学JS,都会讲到变量提升这一概念

a = 10 
var a;
console.log(a) // 10 not undifined

function foo() {}

var bar = function(){} // 这里是先声明bar,给bar设置默认值 undifined,然后再用一个函数赋值

要想真正理解变量提升的来龙去脉,就得去理解 JS 代码得执行流程

以一段代码为例,让理解 JS 代码的完整执行流程

foo()
console.log(bar)
var bar = 'JS'
function foo(){
	console.log('foo')
}

这样一段代码是怎样被浏览器的引擎来执行的?

  • 首先,foo 函数和 var 变量在代码中的物理位置是不会发生改变的,即两者的使用都在声明之前
  • 将这段代码输入给浏览器中的JS引擎后,JS引擎首先会将这段代码存入内存,并开始编译
  • 编译完成后,就开始交给 CPU 开始执行

编译阶段

而变量提升的原因,就在编译阶段,我们重点关注编译后的代码,以及整个代码的内存状况

上面这段代码经过编译后,会在内存中生成两个部分

  • 执行上下文
    执行上下文是JS执行代码的运行环境,类似操作系统中的上下文概念。它包括变量环境和词法环境。
    而变量提升的奥秘主要就藏在变量环境之中。
    变量提升后的内容被保存在了变量环境之中,使得可执行代码可以使用物理位置上还没声明的变量,JS引擎在编译阶段会检测代码中的变量,并将其保存在变量环境之中
  • 可执行代码
    在JS引擎将代码中的所有声明的变量保存在变量环境后,JS会将声明变量以外的代码编译为字节码,即可执行代码
    下面就是上面这段代码编译后生成的可执行代码
foo()
console.log(bar)
bar='JS'

执行阶段

JS引擎开始执行可执行代码,按照顺序一行一行执行,像解释型语言一样。接下来我们一行一行分析可执行代码的执行流程

  • foo() 函数调用,JS引擎会在变量环境中寻找foo函数,因为变量环境中存在foo函数的引用(因为JS对象都是存在堆区的),所以JS会调用该函数,打印 foo
  • console.log(bar),同样JS引擎会在变量环境中寻找 bar 变量,因为变量环境中存在 bar,其值为默认值 undifined,所以打印输出 undifined
  • bar=‘JS’,将 JS 赋值给 bar 变量,在赋值完成后,变量环境中的bar变量的值也会更新

以上就是JS代码的大概的执行流程