JavaScript高级JavaScript的运行原理:V8引擎,JS代码执行原理,作用域和作用域链面试题
Posted karshey
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript高级JavaScript的运行原理:V8引擎,JS代码执行原理,作用域和作用域链面试题相关的知识,希望对你有一定的参考价值。
文章目录
V8引擎
浏览器内核是由两部分组成的,以webkit为例:
- WebCore:负责html解析、布局、渲染等等相关的工作
- JavaScriptCore:解析、执行javascript代码。
有一个强大的JavaScript引擎就是V8引擎。
架构
Parse模块会将JavaScript代码转换成AST(抽象语法树),因为解释器并不直接认识JavaScript代码。如果函数没有被调用,是不会被转成AST的。
Ignition是一个解释器,会将AST转换成ByteCode(字节码)。同时会收集TurboFan优化所需要的信息(如函数参数的类型信息)。如果函数只调用一次,Ignition会解释执行ByteCode;
TurboFan是一个编译器,可以将字节码编译为CPU可以直接执行的机器码。
- 如果一个函数被多次调用,那么就会被标记为热点函数,那么就会经过TurboFan转换成优化的机器码,提高代码的执行性能。
- 机器码也会被还原为ByteCode,因为如果后续执行函数的过程中,类型发生了变化,之前优化的机器码并不能正确的处理运算,就会逆向的转换成字节码
如:
function sum(num1,num2)
return num1+num2
若多次调用sum(10,20)
,则它会被标记为热点函数,且优化为机器码。这里的数据类型都是Number,执行的操作是加法。
但这里也可以传入两个字符串,执行的操作是字符串拼接,若如此,之前优化的机器码就要逆向地转换成字节码。
JavaScript代码执行原理
初始化全局对象
js引擎会在执行代码之前,会在堆内存中创建一个全局对象:Global Object(GO)
- 该对象 所有的作用域(scope)都可以访问
- 里面会包含Date、Array、String、Number、setTimeout、setInterval等
- 有一个window属性指向自己
执行上下文 Execution Contexts
js引擎内部有一个执行上下文栈(Execution Context Stack,简称ECS),它是用于执行代码的调用栈。执行的是全局的代码块:
- 全局的代码块为了执行会构建一个全局执行上下文 Global Execution Context(GEC)
- GEC会 被放入到ECS中 执行
GEC被放入到ECS中里面包含两部分内容:
- 代码执行前,在parser转成AST的过程中,会将全局定义的变量、函数等加入到GlobalObject中,但是并不会赋值——这个过程也称之为变量的作用域提升(hoisting)
- 在代码执行中,对变量赋值,或者执行其他的函数
VO对象
每一个执行上下文会关联一个VO(Variable Object,变量对象),变量和函数声明会被添加到这个VO对象中
举个例子:
var message = "Global Message"
function foo()
message = "foo message"
var num1 = 30
var num2 = 20
var res = num1 + num2
console.log(res);
这段代码被parse(即转化为AST)时,会有一个VO对象。这段代码里的message、foo、num1、num2、res的声明都会被放到这个VO对象中(注意,函数是提前声明的),但是还没赋值。相当于:
VO:
//创建函数对象,值(键值对的值)是指向函数对象的指针
foo:0xa00,
message:undefined,
num1:undefined,
num2:undefined,
res:undefined,
如果执行上下文是全局执行上下文的话,VO就是GO。
函数的执行
执行一个函数时,会根据函数体创建一个函数执行上下文(Functional Execution Context,简称FEC),并且压入到EC Stack中。
这里的VO是AO(Activation Object),它会使用arguments作为初始化,并且初始值是传入的参数,AO会存放变量的初始化。
作用域和作用域链的面试题
看看这个:Js作用域与作用域链详解
面试题:
1
var n = 100
function foo()
n = 200
foo()
console.log(n);
答:
200
2
function foo()
console.log(n);
n = 200
console.log(n);
var n = 100
foo()
答:
100
200
3
var n = 100
function foo1()
console.log(n);
function foo2()
var n = 200
console.log(n);
foo1()
foo2()
console.log(n);
答:
200
100
100
解析:
- foo2里的n是200
- 调用foo1,foo1里没有n,所以去它的上层作用域找:它的上层作用域是全局——与调用的位置无关,与定义的位置有关,所以全局里的n是100
- 全局里的n是100
4
var a = 100
function foo()
console.log(a);
return
var a = 100
foo()
答:
undefined
解析:foo里有a!代码其实相当于:
var a = 100
function foo()
var a
console.log(a);
//return 后的不会执行
//return
//a = 100
foo()
所以输出是undefined。
5
function foo()
var a = b = 100
foo()
console.log(a);
console.log(b);
解析:
- 访问不到a,因为a只在foo函数作用域里,在全局里没有
- 访问得到b,因为b没有用var声明,于是会被js解析成全局变量,b为100
参考
coderwhy的课
JavaScript代码到底是怎么执行的?
站在‘上帝 ’角度,透视v8 执行 js 的过程
Js作用域与作用域链详解
以上是关于JavaScript高级JavaScript的运行原理:V8引擎,JS代码执行原理,作用域和作用域链面试题的主要内容,如果未能解决你的问题,请参考以下文章