Please enable Javascript to view the contents

从头学习js-7-执行上下文汇总篇

 ·  ☕ 4 分钟

这个系列是我读冴羽老师博客的感悟,
加入了个人的解读和练习题的解答

本篇是3、4、5、6篇的汇总,会用两个例子来详细说明执行上下文的运行流程

例子1

1
2
3
4
5
6
7
8
9
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope();

1.执行全局代码,创建全局上下文,全局上下文压入执行上下栈

1
2
3
ECStack = [
  globalContext
]

2.初始化全局上下文

1
2
3
4
5
globalContext = {
  VO: [global],
  scope: [globalContext.VO],
  this: globalContext.VO
}

2.初始化的同时,创建checkScope函数,checkscope函数保存作用域链到函数内部属性

1
checkscope.[[scope]] = [globalContext.VO];

3.执行checkscope函数,创建checkScope执行上下文,压入执行上下文栈

1
2
3
4
ECStack = [
  checkscopeContext,
  globalContext
]

4.初始化checkScope执行上下文,
4.1复制checkscope函数的内部属性[[scope]]创建作用域链
4.2用arguments创建AO活动对象,
4.3初始化活动对象,即加入函数形参,函数声明,变量声明
4.4将活动对象压入checkscope的作用域顶端

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
checkscopeContext = {
  AO: {
    arguments: {
      length: 0
    },
    scope: undefined,
    f: reference to fucntion f(){}
  },
  scope: [AO, globalContext.VO],
  this: undefined
}

同时f函数被创建,保存作用域链到f函数内部属性[[scope]]

1
f.[[scope]] = [checkscopeContext.AO, globalContext.VO];

5.执行f函数,创建f函数执行上下文,将其压入执行上下文栈

1
2
3
4
5
ECStack = [
  fContext,
  checkscopeContext,
  globalContext
]

6.f函数执行上下文初始化,
6.1复制函数[[scope]]属性创建作用域链
6.2用arguments创建活动对象
6.3舒适化活动对象,即加入形参,函数声明,变量声明
6.4将活动对象压入f作用域顶端

1
2
3
4
5
6
7
8
9
fContext = {
  AO: {
    arguments: {
      length: 0
    },
  },
  scope: [AO, checkScopeContext.AO, globalContext.VO],
  this: undefined
}

7.执行函数f,沿着作用域链找到scope的值,返回scope的值

8.函数f执行完毕后,在ECStack中出栈

1
2
3
4
5
ECStack.pop()
ECStack = [
  checkscopeContext,
  globalContext
]

9.函数checkScope执行完毕后在ECStack出栈,

1
2
3
4
ECStack.pop()
ECStack = [
  globalContext
]

例子2

例子2和例子很相似

1
2
3
4
5
6
7
8
9
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()();

1.开始执行全局代码,创建全局上下文,并将其压入上下文执行栈

1
2
3
ECStack = [
  globalContext
]

2.初始化全局上下文

1
2
3
4
5
globalContext = {
  VO: [global],
  scope: globalContext.VO,
  this: globalContext.VO
}

2.初始化的同时创建函数checkscope,函数checkScope保存作用域链到其内部属性[[scope]]

1
checkscope.[[scope]] = [globalContext.VO];

3.执行函数checkScope,创建checkScope函数的执行上下文,并将其压入上下文执行栈

1
2
3
4
ECStack = [
  checkScopeContext,
  globalContext
]

4.初始化checkScope执行上下文,
4.1保存函数的内部属性[[scope]]到执行上下文的作用域链
4.2根据函数的arguments创建活动对象AO
4.3初始化活动对象,即加入函数形参,函数声明,变量声明
4.4将活动对象压入checkscope作用域的顶端

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
checkScopeContext = {
  AO: {
    arguments: {
      length: 0
    },
    scope: undefined,
    f: reference to fucntion f(){}
  },
  scope: [AO, globalContext],
  this: undefined
}

4.同时创建函数f,保存作用域链到f函数内部属性[[scope]]

1
f.[[scope]] = [checkscopeContext.AO, globalContext.VO];

5.沿着作用域找到函数f的指向,返回函数f的指向,函数checkScope执行完毕后在ECStack出栈

1
2
3
4
ECStack.pop()
ECStack = [
  globalContext
]

6.执行checkScope返回的函数f,创建函数f的执行上下文,将其压入执行上下文栈

1
2
3
4
ECStack = [
  fContext,
  globalContext
]

7.初始化f的执行上下文fContext
7.1复制函数内部属性scope到函数上下文的作用域链
7.2根据函数的arguments创建活动对象AO
7.3初始化活动对象,即加入函数形参,函数声明,变量声明
7.4将活动对象压入函数上下文作用域链的顶端

1
2
3
4
5
6
7
8
9
fContext = {
  AO: {
    arguments: {
      length: 0
    }
  }
  scope: [AO, checkScopeContext.AO, globalContext]
  this: undefined
}

8.执行函数f,沿着作用域链找到scope的值(这里是在checkScopeContext.AO里找到scope的,即便checkScopeContext.AO已经在ECStack中出栈,这就是闭包的原理),返回scope的值

7.函数f执行完毕后,f的执行上下文从执行上下文栈中弹出

1
2
3
4
ECStack.pop()
ECStack = [
  globalContext
]
分享

Llane00
作者
Llane00
Web Developer