假如我们有下面一段代码,它在JavaScript中是如何执行的呢
初始化全局对象:
js引擎会在
执行代码之前
,会在
堆内存中创建一个全局对象
:Global Object(GO)
-
该对象 所有的作用域(scope) 都可以访问;
-
里面会包含 Date、Array、String、Number、setTimeout、setInterval 等等;
-
其中还有一个 window属性 指向自己;
执行上下文栈(调用栈)
- js引擎内部有一个执行上下文栈(Execution Context Stack,简称ECS),它是用于执行代码的调用栈。
-
那么现在它要执行谁呢?执行的是 全局的代码块 :
-
全局的代码块为了执行会构建一个 Global Execution Context(GEC) ;
-
GEC会 被放入到ECS中 执行;
- GEC被放入到ECS中里面包含两部分内容:
-
第一部分: 在代码执行前,在 parser转成AST的过程 中,会将 全局定义的变量、函数 等加入到 GlobalObject 中,但是并 不会赋值 ;这个过程也称之为 变量的作用域提升(hoisting)
- 第二部分:在代码执行中,对变量赋值,或者执行其他的函数;
GEC被放入到ECS中
GEX开始执行代码
遇到函数如何执行?
- 在执行的过程中执行到一个函数时,就会根据函数体创建一个函数执行上下文(Functional Execution Context, 简称FEC),并且压入到EC Stack中
-
FEC中包含三部分内容:
-
第一部分:在解析函数成为AST树结构时,会创建一个Activation Object(AO):AO中包含形参、arguments、函数定义和指向函数对象、定义的变量;
-
第二部分:作用域链:由VO(在函数中就是AO对象)和父级VO组成,查找时会一层层查找;
-
第三部分:this绑定的值:这个我们后续会详细解析;
FEC被放入到ECS中
FEC开始执行代码
函数执行:
- 当函数执行上下文在调用栈中执行完后,这个函数执行上下文就会移出调用栈并销毁,然后AO就会销毁
- 当我们查找变量时,真实的查找路径是沿着作用域链里查找的(scope chain:AO + GO)
变量环境和记录
其实我们上面的讲解都是基于早期ECMA的版本规范:
在最新的ECMA的版本规范中,对于一些词汇进行了修改:
通过上面的变化我们可以知道,在最新的ECMA标准中,我们前面的变量对象VO已经有另外一个称呼了变量环境 VE
作用域提升面试题
认识内存管理:
JS的内存管理:
JS的垃圾回收:
常见的GC算法-引用计数
常见的GC算法-标记清除