1、JavaScript的执行过程
假如我们有下面一段代码,他在JavaScript中是如何被执行的呢?
var name = "why"console.log(num1)var num1 = 20var num2 = 30var result = num1 + num2console.log(result)
1.1初始化全局对象
- js引擎会在执行代码之前,会在堆内存中创建一个全局对象:Global Object(GO)
- 该对象 所有的作用域(scope)都可以访问;
- 里面会包含Date、Array、String、Number、setTimeout、setInterval等等;
- 其中还有一个window属性指向自己;
1.2执行上下文栈(调用栈)
- js引擎内部有一个执行上下文栈(Execution Context Stack,简称ECS),它是用于执行代码的调用栈。
- 那么现在它要执行谁呢?执行的是全局的代码块:
- 全局的代码块为了执行会构建一个 Global Execution Context(GEC);
- GEC会 被放入到ECS中 执行;
GEC被放入到ECS中里面包含两部分内容:
在执行的过程中执行到一个函数时,就会根据函数体创建一个函数执行上下文(Functional Execution Context, 简称FEC),并且压入到EC Stack中。
FEC中包含三部分内容:
- 第一部分:在解析函数成为AST树结构时,会创建一个Activation Object(AO):
- AO中包含形参、arguments、函数定义和指向函数对象、定义的变量;
- 第二部分:作用域链:由VO(在函数中就是AO对象)和父级VO组成,查找时会一层层查找;
第三部分:this绑定的值:这个我们后续会详细解析;

1.6 FEC被放入到ECS中
- 第一部分:在解析函数成为AST树结构时,会创建一个Activation Object(AO):
1.7 FEC开始执行代码

2、变量环境和记录
其实我们上面的讲解都是基于早期ECMA的版本规范:
在最新的ECMA的版本规范中,对于一些词汇进行了修改:
通过上面的变化我们可以知道,在最新的ECMA标准中,我们前面的变量对象VO已经有另外一个称呼了变量环境
VE。
3.作用域提升面试题
3.1 面试题1
var n = 100function foo() {//在函数作用域内没有找到变量n,所以将n=200赋值到全局作用域n中n = 200}foo()console.log(n) //200
3.2 面试题2
function foo() {console.log(n) //undefinedvar n = 200console.log(n) // 200}var n = 100foo()
3.3 面试题3
var n = 100function foo1() {console.log(n); // 2. 100}function foo2() {var n = 200console.log(n); // 1. 200foo1()}foo2()console.log(n); // 3. 100
3.4 面试题4
var a = 100function foo() {console.log(a) // undefindreturnvar a = 200}foo()
3.5 面试题5
function foo() {// 如果再函数中没有定义变量//js引擎会在全局作用域中自动定义同名变量m = 100}foo()console.log(m) // 100
function foo() {var a = b = 10// => 转成下面的两行代码// var a = 10// b = 10//b会自动在全局作用域中创建}foo()// console.log(a) 会报错console.log(b) // 10
