本文已参与「新人创作礼」活动,一起开启掘金创作之路。
JS执行流程
1.执行前
-
对源代码进行词法分析、语法分析, 创建执行栈(ECS, Excution Context Stack),与一个堆空间
-
创建一个全局执行上下文(GEC,Golbal Excution Context)
-
在堆空间创建一个GO(Golbal Object),如果运行环境是浏览器这个GO就是window,那么就会创建一些全局属性如Date,Math,String,Number等,且还有一些代码中声明的全局作用域下的变量与函数并初始化。例如
-
var message = '123' function foo(num) { var name = 'zhangsan', var age = 18 var doubleNum = num * 2 } foo(2)
-
变量的message初始值为undefined
-
函数较为特殊, 解析到函数foo时则会创建一个函数对象,这个函数对象会初始化一些函数的属性(如length, name, arguments,[[ Scope]] 以及 函数代码 等),并这个对象的地址值赋给GO的foo属性(注意函数的作用域 [[ scope ]] 已经确定且为GO)
-
创建一个EC并将其压栈(ECS)。这个EC为GEC,因为每创建一个EC就会关联一个VO(Variable Object), this, Scope Chain,此时GEC的VO会指向GO, this为undefined, Scope Chain为GO
2. 开始代码
- (步骤1.7)GEC中的this赋值为window
- message赋值操作, GO中的message属性变为
'123'
- 执行foo函数之前
- 在堆空间创建一个AO(Active Object),AO中进行初始化,函数体中声明的变量为undefined, 函数体中声明的函数则会被赋值新函数对象的地址值(重复1.3-1.4的操作)作为AO的属性。例子中,会创建属性num, name, age, doubleNum,值为undefined
- 创建一个EC并将其压栈(ECS)。这个EC为FEC(Function Excution Context),这FEC会关联一个VO,而此时的VO就是步骤2.3中创建的AO。此时的this为undefined,Scope Chain为AO + [[ Scope ]],(这个[[ Scope ]]就是步骤1.6中那个[[ Scope ]])
- 开始执行函数
- FEC中的this赋值, 根据调用方式来判断。此例子中属于时独立调用,this会被隐式绑定为GO
- num赋值
- name赋值
- age赋值
- doubleNum赋值
- 函数执行完成
- FEC被弹出ECS
- (可能会出现的步骤)AO对象被垃圾回收(GC, Garbage Collection)
3. 所有代码执行完成
- GEC被弹出ECS
- 堆空间中的所有对象被垃圾回收