概要
本文主要通过一个实例,来理解什么是Javascript中的Execution Context,以及在JavaScript执行过程中,Execution Context是如何工作的。
基本概念
事实上,我们可以理解为JavaScript代码在一个盒子中执行,而这个盒子本身就是我们的Execution Context。
代码在执行过程中,可以在这个盒子中找到需要的变量,函数等信息。
对于复杂的JavaScript项目,代码量庞大,代码运行过程中可能需要多个Execution Context,这些Execution Context按照类型,可以划分为Global Execution Context (GEC) 和 Function Execution Context (FEC)。
- GEC是基本的执行上下文,它的代码层级最高且只有一个,用于创建全局对象和将this绑定到全局对象上。
- FEC是函数的执行上下文,在函数被调用的时候由JS Engine创建,可以有多个。
所有的JavaScript代码都要在 Call Stack中执行,Call Stack将上述的Execution Context 组织在一起,由JS Engine逐行执行。
实例
下面我看一段简单的JavaScript代码
var a = 0;
test1();
test2();
console.log(a);
function test1() {
var a = 10;
console.log(a);
}
function test2() {
var a = 20;
console.log(a);
}
代码执行结果如下:
下面我们按照JS Engine的运行方式,解释一下代码是如何执行的
Step 1 建立 GEC
在创建GEC的时候,并不会对将变量值载入本地内存,这个时候变量a的值只是undefined,但是test1和test2S是两个全局的函数,会被载入本地内存。
我们设置好断点,可以看到,代码执行如我们上面示意图期待的那样
此时GEC进入Call Stack
Step 2 执行 GEC中的Global代码
执行赋值操作如下:
赋值操作执行后,本地内存中变量a由undefined变成0,代码执行后,从Call Stack中删除
在浏览器中,GEC的a变量也被赋值为0
Step 2 执行 GEC中的test1函数
test1是一个函数,一旦被调用,该函数立刻进入Call Stack,JS Engine会为它创建一个独立的FEC。
初始状态下,a变量是undefined。函数开始I执行后,a被赋值为10,即FEC中的a变量被赋值为10。
此时GEC中的a变量并不会影响FEC中的a变量。JS Engine会先在自己的FEC中查看是否有变量a,如果找到,就会直接使用。
浏览器中断点的截图如下:
在test1方法执行完成后,函数的FEC,变量和函数代码全部从Call Stack移除。
Step 3 执行 GEC中的test2函数
test2也是一个函数,一旦被调用,该函数会立刻进入Call Stack,JS Engine会为它创建一个独立的FEC。
初始状态下,a变量是undefined。函数开始I执行后,a被赋值为20,FEC中的a变量被赋值为20。
此时GEC中的a变量并不会影响FEC中的a变量。JS Engine会先在自己的FEC中查看是否有变量a,如果找到,就会直接使用。
浏览器中断点的截图如下:
在test2方法执行完成后,函数的FEC,变量和函数代码全部从Call Stack移除。
Step 4 执行完成
删除GEC,释放内存空间。从截图中我们可以看到,浏览器中所有相关的代码,变量和函数全部被删除了。