持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情
前言
上一节简单了解了js的v8引擎,那么大家好奇js代码是怎样在v8引擎里运行的吗?下边我们来解析下全过程
第一步代码被解析
先来简单的回顾下上一章说到的一个流程图
大概是这么个过程,那么当你写下一行js代码的时候它是怎么运行的呢?
我们来举个例子,先来看一段简单的代码
var name = 'juejin'
var age = '77'
var school = 'juejin'
上述代码定义了三个简单的变量,这个时候我们的js引擎做了如下的几件事
当代码被解析的时候,v8引擎会帮我们创建一个 GlobalObject对象,也就是上图javascript源码到parse这一步,也就是代码的解析阶段,这个GlobalObject对象会包含js中最初始的一些类,例如date,string,Math,settimeout等,正是有了GlobalObject对象我们才能直接使用上述全局的一些类,这个GlobalObject对象不仅仅是创建了一些常用的类,还创建了一个window的属性,指向了自己. 来看下下面的伪代码就全明白了.
var GlobalObject = {
String:'类',
Date:'类',
settimeout:'函数',
window:GlobalObject
}
因为是在解析代码,所以这个v8引擎会把我们定义的变量也放到了这个 GlobalObject的变量中,因为此时代码还没有被执行,所以此时它们的值还都是undefined ,因为只有执行的时候才会给它赋值,在解析阶段只是知道你有这么个属性
var GlobalObject = {
String:'类',
Date:'类',
settimeout:'函数',
window:GlobalObject,
name:undefined,
age:undefined,
school:undefined
}
这个 GlobalObject 还有个名字就叫GO,以后我们都这么叫它
第二步,代码的运行
- v8引擎为了执行我们的代码,它内部会有一个
执行上下文栈也就是函数调用栈,英文名称Execution Context Stack, 简称ECStack。所有代码的执行都需要放到这个栈里,一般是放入的函数
- 因为我们执行的是全局代码,为了全局代码能够正常执行,需要创建一个
全局执行上下文(Global Execution Context),它只会在全局代码需要执行的时候,才会被创建,然后放入我们的执行上下文(ECStack),这个全局执行上下文中还有创建一个叫VO (variable object)的对象,它指向的其实就是之前创建的GO
- 接下来才是真正的执行代码,当代码遇到
name变量时,从vo里找这个变量,因为vo指向go,也就是从go里找,这个时候会把3. 接下来才是真正的执行代码,当代码遇到name变量时,从vo里找这个变量,因为vo指向go,也就是从go里找,这个时候会把go里的name由undefined改为juejin,后续的变量也是一样的道理。
变量提升
这个时候,如果我们在代码的最后一行打印一个console.log(name),它就会去我们的vo里找name,这个时候自然而然的是juejin
var name = 'juejin'
var age = '77'
var school = 'juejin'
console.log(name)
代码执行结果如下
如果我们这时候在代码的第二行打印一下age呢,它会打印什么呢,因为在go中存在这个变量,因为给它赋值的代码还没有被执行,因此它的值这个时候是undefined,而不会报错说找不到这个变量,这个就是常说的变量提升,也叫作用域提升
var name = 'juejin'
console.log(age)
var age = '77'
var school = 'juejin'
console.log(name)
代码执行结果如下