全局代码执行和作用域提升

144 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

1、代码被解析

        代码被解析时V8引擎的parse模块会帮我们创建一个GlobalObject(GO)对象,里面包含,String, DateNumber, setTimeout, setInterval等等,并且还有一个window属性,属性值为this,指向这个对象(GO)

伪代码:

var GlobalObject = {
    String: '类', 
    DateNumber: '类',
    setTimeout: '类',
    setInterval: '类',
    ......
    window: GlobalObject
}

因为window拿到的还是这个对象,所以可以这样一直.window

console.log(window.window.window.window)

然后就是开始对代码进行解析

比如这串代码

var num1 = 20
var num2 = 30
var result = num1 +num2
function foo () {

}

创建GlobalObject对象后是这样的(伪代码)

var GlobalObject = {
    String: '类', 
    DateNumber: '类',
    setTimeout: '类',
    setInterval: '类',
    ......
    window: GlobalObject,
    foo: undefined
    num1 = undefined
    num2 = undefined
    result = undefined
}

总结:

        js引擎会在执行代码之前,会在堆内存中创建一个全局对象:Global Object(GO)

        该对象所有的作用域(scope)都可以访问

        里面会包含Date、Array、String、Number、setTimeout、setInterval等等

        其中还有一个window指向自己

2、运行代码

        V8引擎为了执行代码,内部会有一个执行上下文栈(函数调用栈  Execution Context Stack, ECStack)

        因为我们执行的是全局代码,为了全局代码能够正常执行,需要创建全局执行上下文(Global Execution Context,GEC)(全局代码被执行时才会创建)

附图解析

​编辑

 执行代码是下面代码从上往下依次执行执行

var num1 = 20
var num2 = 30
var result = num1 +num2
function foo () {

}

 在执行num1代码时会找到VO,也就是GO,把GO里的num1属性值改成20,以此类推

在var声明的num1之前去console.log(num1)是不会报错的,而是undefined,就是因为GO对象,也就是所谓的作用域提升

总结

  • 代码被解析,初始化全局对象go。go中会对变量的作用域进行提升,且默认初值为undefined
  • 代码执行前,全局上下文(GEC中的vo指向go对象)进入执行上下文栈 (ECS)
  • 代码依次执行,依次为go中的变量赋值。