一篇文章弄懂javascript中的执行栈与执行上下文


Posted in Javascript onAugust 09, 2019

前言

作为一个前端开发人员,弄清楚JavaScript的执行上下文有助于我们理解js中一些晦涩的概念,比如闭包,作用域,变量提升等等。

执行栈

执行栈用于存储代码执行期间创建的所有执行上下文。具有FILO接口,也被称为调用栈。
当JavaScript代码被运行的时候,会创建一个全局上下文,并push到当前执行栈。之后当发生函数调用的时候,引擎会为函数创建一个函数执行上下文并push到栈顶。引擎会先执行调用栈顶部的函数,当函数执行完成后,当前函数的执行上下文会被移除当前执行栈。并移动到下一个上下文。

let a = 'Hello'

function first() {
  console.log('Inside first function')
  second()
  console.log('Again inside first function')
}

function second() {
  console.log('Inside second function')
}

first()

console.log('Inside Global execution context')

一篇文章弄懂javascript中的执行栈与执行上下文

执行上下文

我们可以理解为执行上下文是js代码被解析和执行时所在环境的抽象概念。
JavaScript的执行上下文分为三种类型:

  • 全局执行上下文:最基本的上下文,只有一个。创建了一个全局对象(eg:浏览器中的window),将this指向全局对象。
  • 函数执行上下文:每次调用函数都会创建一个函数上下文。函数上下文可以存在无数个。
  • Eval函数执行上下文:运行在eval函数中的代码会有一个自己的执行上下文(本文不讨论)。

执行上下文的创建

创建执行上下文又可以分为两个阶段: 1. 创建阶段 2. 执行阶段

创建阶段

在创建阶段,JavaScript引擎会创建LexicalEnvironment(词法环境)组件,VariableEnvironment(变量环境)组件以及this绑定(在全局上下文中,this指向全局对象。在函数执行上下文中,this取决与函数在哪里被调用。)

Lexical  Environment(词法环境)

ES2015规范对词法环境的描述

我们可以理解为词法环境是一种包含标识符(变量/函数的名称)和变量(实际对象:函数/原始值/数组对象等)映射的数据结构。

每个词法环境由两部分组成:Environment Record环境记录(存储变量和函数声明的实际位置)和对外部环境的引用(可以访问其外部词法环境)

环境记录分为两种:

  • Declarative environment record(声明性环境记录): 存储变量和函数声明。
  • Object environment record(对象环境记录):全局词法环境。除了变量和函数声明外,对象环境记录还存储全局绑定对象。

tips:对于函数执行上下文来说,环境记录还包含了一个arguments对象,包含了传递给函数的索引和参数之间的映射以及函数参数的数量。

例如:

function foo(a, b) {
  var c = a + b
}

// argument object
Arguments: {0: 2, 1: 3, length: 2}

VariableEnvironment(变量环境)

变量环境也是一个词汇环境,因此它具有上面定义的词法环境的所有属性和组件。在ES6中,LexicalEnvironment组件和VariableEnvironment组件之间的一个区别是前者用于存储函数声明和变量let和const绑定,而后者仅用于存储变量var绑定。

执行阶段

在执行阶段,会完成对所有变量的分配,代码也会被最终执行。执行上下文的代码会被分成两个阶段:

  1. 进入执行上下文
  2. 代码执行
let a = 20
const b = 30
var c

function multiply(e, f) {
  var g = 20
  return e * f * g
}

c = multiply(20, 30)

当上面的代码被执行的时候,JavaScript引擎会创建一个全局上下文来执行全局代码。

此时的全局上下文:

GlobalExectionContext = {  // 全局上下文
  LexicalEnvironment: {  // 词法环境
    EnvironmentRecord: {  // 环境记录
      type: 'Object', // 类型
      // 标识符
      a: <uninitialized>,
      b: <uninitialized>,
      multiply: <func>
    },
    outer: <null>, // 对外部环境引用
  },
  VariableEnvironment: { // 变量环境
    EnvironmentRecord: {  // 环境记录
      type: 'Object',
      c: undefined
    },
    outer: <null>, // 对外部环境引用
  },
  ThisBinding: <Global Object>  // this绑定
}

在执行阶段,变量会被赋值,此时的全局上下文变成:

GlobalExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      type: 'Object',
      a: 20,
      b: 30,
      multiply: <func>
    },
    outer: <null>
  },
  VariableEnvironment: {
    EnvironmentRecord: {
      type: 'Object',
      c: undefined
    }
    outer: <null>
  },
  ThisBinding: <Global Object>
}

当JavaScript引擎遇到函数multiply(20, 30)的时候,会创建一个新的函数上下文:

FunctionExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      type: 'Declarative',
      arguments: {
        0: 20,
        1: 30,
        length: 2
      }
    },
    outer: <GlobalLexicalEnvironment>
  },
  VariableEnvironment: {
    EnvironmentRecord: {
     Type: "Declarative",
     g: undefined
    },
    outer: <GlobalLexicalEnvironment>,
  },
  thisBinding: <Global Object or undefined>
}

之后执行上下文会进入执行阶段, 此时的函数上下文:

FunctionExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      type: 'Declarative',
      arguments: {
        0: 20,
        1: 30,
        length: 2
      }
    },
    outer: <GlobalLexicalEnvironment>
  },
  VariableEnvironment: {
    EnvironmentRecord: {
     Type: "Declarative",
     g: 20
    },
    outer: <GlobalLexicalEnvironment>,
  },
  thisBinding: <Global Object or undefined>
}

当函数执行完毕后。会返回一个值并赋值给变量c,全局上下文被更新。更新完成后,代码执行完毕,程序结束。

参考文章

Understanding Execution Context and Execution Stack in Javascript

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
jQuery数组处理方法汇总
Jun 20 Javascript
JS操作select下拉框动态变动(创建/删除/获取)
Jun 02 Javascript
js输入框邮箱自动提示功能代码实现
Dec 10 Javascript
jquery下div 的resize事件示例代码
Mar 09 Javascript
JavaScript function 的 length 属性使用介绍
Sep 15 Javascript
原生JavaScript编写俄罗斯方块
Mar 30 Javascript
js实现简单折叠、展开菜单的方法
Aug 28 Javascript
JavaScript阻止回车提交表单的方法
Dec 30 Javascript
在Html中使用Requirejs进行模块化开发实例详解
Apr 15 Javascript
对比分析Django的Q查询及AngularJS的Datatables分页插件
Feb 07 Javascript
微信小程序仿今日头条导航栏滚动解析
Aug 20 Javascript
微信小程序添加插屏广告并设置显示频率(一天一次)
Dec 06 Javascript
vue中组件通信的八种方式(值得收藏!)
Aug 09 #Javascript
Vue全局loading及错误提示的思路与实现
Aug 09 #Javascript
使用Vue CLI创建typescript项目的方法
Aug 09 #Javascript
详解vue beforeRouteEnter 异步获取数据给实例问题
Aug 09 #Javascript
微信小程序如何连接Java后台
Aug 08 #Javascript
vue 实现Web端的定位功能 获取经纬度
Aug 08 #Javascript
Vue-cli3.X使用px2 rem遇到的问题及解决方法
Aug 08 #Javascript
You might like
php 网上商城促销设计实例代码
2012/02/17 PHP
php实现随机生成易于记忆的密码
2015/06/19 PHP
js AspxButton的客户端操作
2009/06/26 Javascript
购物车选中得到价格实现示例
2014/01/26 Javascript
jQuery实现的导航条切换可显示隐藏
2014/10/22 Javascript
jQuery中insertAfter()方法用法实例
2015/01/08 Javascript
JQuery自适应窗口大小导航菜单附源码下载
2015/09/01 Javascript
浅谈Nodejs应用主文件index.js
2016/08/28 NodeJs
Actionscript与javascript交互实例程序(修改)
2016/09/22 Javascript
JavaScript该如何学习 怎样轻松学习JavaScript
2017/06/12 Javascript
详解AngularJS之$window窗口对象
2018/01/17 Javascript
用Vue写一个分页器的示例代码
2018/04/22 Javascript
教你30秒发布一个TypeScript包到NPM的方法步骤
2019/07/22 Javascript
Vue实现将数据库中带html标签的内容输出(原始HTML(Raw HTML))
2019/10/28 Javascript
JS实现商城秒杀倒计时功能(动态设置秒杀时间)
2019/12/12 Javascript
[36:17]DOTA2上海特级锦标赛 - VGL音乐会全集
2016/03/06 DOTA
Python 时间操作例子和时间格式化参数小结
2014/04/24 Python
Python中设置变量访问权限的方法
2015/04/27 Python
Python实现基于权重的随机数2种方法
2015/04/28 Python
为Python程序添加图形化界面的教程
2015/04/29 Python
Python合并两个字典的常用方法与效率比较
2015/06/17 Python
python3+PyQt5使用数据库表视图
2018/04/24 Python
python实现朴素贝叶斯算法
2018/11/19 Python
使用pycharm设置控制台不换行的操作方法
2019/01/19 Python
关于Python形参打包与解包小技巧分享
2019/08/24 Python
python numpy之np.random的随机数函数使用介绍
2019/10/06 Python
Python文件操作函数用法实例详解
2019/12/24 Python
Python 解决火狐浏览器不弹出下载框直接下载的问题
2020/03/09 Python
Python实现列表中非负数保留,负数转化为指定的数值方式
2020/06/04 Python
移动web模拟客户端实现多方框输入密码效果【附代码】
2016/03/25 HTML / CSS
HTML文本属性&amp;颜色控制属性的实现
2019/12/17 HTML / CSS
说说你所熟悉或听说过的j2ee中的几种常用模式?及对设计模式的一些看法
2012/05/24 面试题
2014年采购工作总结
2014/11/20 职场文书
初中生思想道德自我评价
2015/03/09 职场文书
辛德勒的名单观后感
2015/06/03 职场文书
2015年秋学期师德师风建设工作总结
2015/10/23 职场文书