前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ES 基础 —— 执行上下文

ES 基础 —— 执行上下文

作者头像
疯狂的技术宅
发布2019-03-28 10:41:17
6380
发布2019-03-28 10:41:17
举报
文章被收录于专栏:京程一灯京程一灯

前言

Execution Context(执行上下文)是 ECMA-262 标准中定义的一个抽象概念,用于同 Executable Code(可执行代码)进行区分。

标准中并没有从技术实现的角度定义 Execution Context 准确类型和结构,以各引擎的具体实现为准。

Executable Code

合法的,可以被解释器解析执行的代码。

Excutable Code 有这么几类:

  • Global Code
  • Function Code:函数体内的代码
  • Eval Code:使用 eval() 函数执行的代码

Execution Context

Execution Context 是 ES 用来跟踪代码运行状态和相关资源集合的特殊机制。它决定了 Executable Code 执行的过程中可以访问的数据。

依据 Excutable Code 的分类, Excution Context 也有相应的分类:

  • Global Execution Context
  • Function Execution Context
  • Eval Execution Context

Execution Context 的基本工作方式

解释基本工作方式的过程中,会涉及到两个名词,先解释一下:

  • Execution Context Stack:用来保存所有 Execution Context 的栈。
  • Running Execution Context:正在使用的 Execution Context。在任意时间,最多只能有一个正在运行代码的 Execution Context。

基本工作方式:Runnig Execution Context 总是在 Execution Context Stack 的顶部,Global Execution Context 总在 Execution Context Stack 的底部。无论什么时候,只要控制权从与当前 Running Execution Context 相关的可执行代码上切换到另一部分与当前 Running Execution Context 不相关的可执行代码上,一个新的 Execution Context 就会被创建,新创建的 Execution Context 会被放在当前的 Runnig Execution Context 的上面,成为新的 Running Execution Context。

╔═══════════════════════════════╗║ ┌─────────────────────────┐ ║║ │Running Execution Context│ ║║ └─────────────────────────┘ ║║ ┌─────────────────────────┐ ║║ │ Execution Context │ ║║ └─────────────────────────┘ ║║ ║║ ■ Execution ║║ ■ Context Stack ║║ ■ ║║ ║║ ┌─────────────────────────┐ ║║ │ Execution Context │ ║║ └─────────────────────────┘ ║║ ┌─────────────────────────┐ ║║ │ Execution Context │ ║║ └─────────────────────────┘ ║║ ┌─────────────────────────┐ ║║ │Global Execution Context │ ║║ └─────────────────────────┘ ║╚═══════════════════════════════╝

Execution Context 的具体工作流程

如前言中提到的,ES 标准中并没有从技术实现的角度定义 Execution Context 准确类型和结构,为了更方便地解释 Excutable Code 和 Execution Context 之间的关系,暂且用数组表示 Execution Context Stack,然后用伪代码来操作 Execution Context Stack(省得画图了):

ECStack = []

解释器在解析 Executable Code 时,为其创建对应的 Execution Context。

Global Code 与 Global Execution Context

ECStack = [globalContext]

Function Code 与 Function Execution Context

需要注意的是,函数代码中不包括内部函数的代码。比如:

(function foo(bar) {if (bar) {return}foo(true);})()

// 第一次调用 fooECStack = [<foo> functionContext,globalContext]// 第二次调用 fooECStack = [<foo> functionContext – recursively,<foo> functionContext,globalContext]

Eval Code 与 Eval Execution Context

Eval Code 引入了一个新的概念 —— Calling Context(调用上下文),这是一个当 eval() 函数被调用时才会产生的 Context,并且 eval() 的活动(变量声明或函数声明)会影响到 Calling Context 。

// influence global contexteval('var x = 10')(function foo() {// and here, variable 'y' is created// in the locale context of 'foo' functioneval('var y = 20')})()console.log(x) // 10console.log(y) // 'y' is not defined

在严格模式中, eval() 将在本地沙盒(local sandbox)中执行,不再影响 Calling Context

上面的例子执行过程中,ECStack 的变化如下:

ECStack = [globalContext]// eval('var x = 10')ECStack.push({context: evalContext,callingContext: globalContext,})// eval exited contextECStack.pop()// foo function callECStack.push(<foo> functionContext)// eval('var y = 20')ECStack.push({context: evalContext,callingContext: <foo> functionContext})// return from evalECStack.pop()// return from fooECStack.pop()

Execution Context 的创建过程

  1. 解释器发现 Executable Code。
  2. 创建 Execution Context 并执行 Executable Code:
    • 在上一步创建的 Execution Context 解释执行 Excutable Code。
    • 创建 Scope Chain(当前 Execution Context 的 VO 和所有词法范畴上的父级 Execution Context 的 VO)。
    • 创建 Variable Object(简称 VO,又名 Activation Object):
    • 创建 this 属性。
    • 对于扫描到的变量声明,在 Variable Object 中创建一个属性:属性名同变量名相同,属性值初始化为 undefined
    • 如果属性名已经存在,什么都不做。
    • 对于扫描到的函数声明,在 Variable Object 中创建一个属性:属性名和函数名相同,属性值是指向内存中函数位置的指针。
    • 如果属性名已经存在,指针将被覆写。
    • Creation Stage (创建阶段):
    • Activation / Code Execution Stage (执行阶段):
    1. 创建 arguments 对象。
    2. 扫描函数声明并创建对应属性:
    3. 扫描变量声明并创建对应属性:

无法通过代码来直接访问 Variable Object,只有解析器才能访问它。 上面,关于 Scope Chain 的中文描述不怎么准确,来看这段英文:The scope chain property of each Execution Context is simply a collection of the current Execution Context’s Variable Object + all parent’s lexical Variable Object. (来源)

举一个例子来解释这个过程:

function foo(i) {var a = 'hello'var b = function privateB() {}function c() {}}foo(22)

调用 foo(22) 的时候,会在 Creation Stage 中创建这样的 Variable Object:

fooExecutionContext = {scopeChain: [ ... ],variableObject: {arguments: {0: 22,length: 1,},i: 22,c: pointer to function c(),a: undefined,b: undefined,},this: { ... }}

能看到,在 Creation Stage 中,虽然定义了属性名,但是并没有对它们初始化。Creation Stage 完成后,开始 Code Execution Stage:

fooExecutionContext = {scopeChain: [ ... ],variableObject: {arguments: {0: 22,length: 1,},i: 22,c: pointer to function c()a: 'hello',b: pointer to function privateB()},this: { ... }}


往期精选文章

一小时内搭建一个全栈Web应用框架

全栈工程师技能大全

一个治愈JavaScript疲劳的学习计划

推翻JavaScript中的三座大山:作用域篇

掌握Chrome开发工具:新一代前端开发技术

WEB前端性能优化常见方法

在 Vue 中创建自定义输入

干货:CSS 专业技巧

四步实现React页面过渡动画效果

理解CSS模块化



小手一抖,资料全有。长按二维码关注京程一灯,阅读更多技术文章和业界动态。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京程一灯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • Executable Code
  • Execution Context
  • Execution Context 的基本工作方式
  • Execution Context 的具体工作流程
    • Global Code 与 Global Execution Context
      • Function Code 与 Function Execution Context
        • Eval Code 与 Eval Execution Context
        • Execution Context 的创建过程
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档