了解javaScript执行上下文和作用域链

90 阅读3分钟

之前对于执行上下文和作用域链总是模模糊糊的,经过几天的学习后,大概有所了解了,就把我这几天学习的总结一下,和大家一起看看。如有错误还望大佬指正!!

var globalScope = "global scope"; 
function checkScope() { 
    var localScope = "local scope"; 
    function innerFunction() { 
            return localScope; 
        } 
    return innerFunction(); 
} 
console.log(checkScope());

这个会打印什么呢,就根据js的运行机制,一起走一遍把

  1. 开始执行:最初,执行栈中只有全局执行上下文ECStack = [globalContext]。这个时候会有一个变量对象的概念VO,全局的变量就保存在globalContext.VO里,可以理解为globalContext.VO = {globalScope: "global scope"}
//当前的执行栈就是
ECStack = [globalContext]
  1. 函数定义阶段:当定义checkScope函数时,会保存父级的变量对象到函数的内部属性[[scope]]里,即checkscope.[[scope]] = globalContext.VO
  2. 函数执行:当checkScope函数执行时,会创建一个checkScopeContext的执行上下文
//当前的执行栈就是
ECStack = [globalContext,checkScopeContext]

4.函数执行前准备:.checkscope函数执行前会做一些准备工作,就是复制函数的[[scope]]属性然后创建作用域,还记得这个属性保存的是什么吗,保存的就是父级的变量对象

//当前的执行栈就是
ECStack = [globalContext,checkScopeContext]
//当前函数的作用域链,Scope属性代表当前函数的作用域链
checkScopeContext={Scope: [ checkScope.[[scope]] ]}

5.函数创建活动对象:接下来checkscope函数会创建活动对象AO,可以理解为和VO意思一样

//当前的执行栈就是
ECStack = [globalContext,checkScopeContext]
//当前函数的作用域链,Scope属性代表当前函数的作用域链
checkScopeContext={
    AO: {
        arguments: {
                length: 0
            },
        localScope: undefined,
        innerFunction: reference to function innerFunction(){},
    },
    Scope: [ checkScope.[[scope]] ]
}
  1. 函数给活动对象赋值:接下来checkscope函数会给AO赋值,并把AO压入作用域链Scope里
//当前的执行栈就是
ECStack = [globalContext,checkScopeContext]
//当前函数的作用域链,Scope属性代表当前函数的作用域链
checkScopeContext={
    AO: {
        arguments: {
                length: 0
            },
        localScope: "local scope",
        innerFunction: reference to function innerFunction(){},
    },
    Scope: [ AO,checkScope.[[scope]] ]
}
  1. 函数准备工作完成开始执行:首先遇到innerFunction函数定义,遇到定义保存父级的变量对象到[[scope]]里,即innerFunction.[[scope]] = checkScopeContext.AO
//当前的执行栈就是
ECStack = [globalContext,checkScopeContext]
  1. 重复上一个函数的执行过程:先复制[[scope]]到作用域链,在创建AO,赋值AO,压入AO到作用链里
//当前的执行栈就是
ECStack = [globalContext,checkScopeContext,innerFunctionContext]
//当前函数的作用域链,scope属性代表当前函数的作用域链
innerFunctionContext = {
    AO: {
        arguments: {
                length: 0
            },
    },
    Scope: [ AO,innerFunction.[[scope]] ]
}
  1. 执行innerFunction函数:return localScopeinnerFunctionContext.Scope作用域链开始查找,先查看AO,发现并没有localScope,再查找innerFunction.[[scope]],这个值就是checkScopeContext.AO,可以发现checkScopeContext.AO里有localScope = local scope,所以就返回local scope
//当前的执行栈就是
ECStack = [globalContext,checkScopeContext,innerFunctionContext]
//当前函数的作用域链,scope属性代表当前函数的作用域链
innerFunctionContext = {
    AO: {
        arguments: {
                length: 0
            },
    },
    Scope: [ AO,innerFunction.[[scope]] ]
}

10.执行innerFunction函数完成:弹出innerFunction执行上下文

//当前的执行栈就是
ECStack = [globalContext,checkScopeContext]

11.执行checkScopeContext函数完成:弹出checkScopeContext执行上下文

//当前的执行栈就是
ECStack = [globalContext]
  1. 代码执行完毕 打印出local scope
var globalScope = "global scope"; 
function checkScope() { 
    var localScope = "local scope";
    function innerFunction() { 
        return localScope; 
    } return innerFunction; 
} 
console.log(checkScope()());

这种情况会打印什么呢,大家说吧!