什么是执行上下文?

  执行上下文就是当前JavaScript代码被解析和执行时所在环境的抽象概念,JavaScript中运行任何的代码都是在执行上下文。

  什么是执行栈?

  执行栈,在其他编程语言中也被叫做调用栈,具有LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文。当JavaScript引擎首次读取脚本时,它会创建一个全局执行上下文并将其推入当前的执行栈。每当发生一个函数调用,引擎都会为该函数创建一个新的执行上下文,并将其推到当前执行栈的顶端。引擎会运行执行上下文在执行栈顶端的函数,当此函数运行完成后,其对应的执行上下文将会从执行栈中弹出,上下文控制权将移到当前执行栈的下一个执行上下文。所以程序结束以前,执行栈最底部永远有一个globalContext。

  执行上下文的类型

  执行上下文总共有三种类型:

  一、全局执行上下文:这是默认的,基础的执行上下文。不在任何函数中的代码都位于全局执行上下文中,做了两件事:1.创建一个全局对象,在浏览器中这个全局对象就是window对象。2.将this指针指向这个全局对象。一个程序中只能存在一个全局执行上下文。

  二、函数执行上下文:每次调用函数时,都会为该函数创建一个新的执行上下文。每个函数都拥有自己的执行上下文,但是只有在函数被调用的时候才会被创建。一个程序中可以存在任意数量的函数执行上下文。每当一个新的执行上下文被创建,它都会按照特定的顺序执行一系列步骤。

  三、Eval函数执行上下文:运行在eval函数中的代码也获得自己的执行上下文,不常用函数,不建议使用。

  执行上下文如何被创建?

  执行上下文分两个阶段创建:1)创建阶段;2)执行阶段

  一、创建阶段:在任意的JavaScript代码被执行之前,执行上下文处于创建阶段。在创建阶段中总共发生了三件事情:

    1.确定this的值,也被称为This Binding;

    2.LexicalEnvironment(词法环境)组件被创建。

    3.VariableEnvironment(变量环境)组件被创建。

创建阶段

    Ⅰ、This Binding:

      在全局执行上下文中,this的值指向全局对象,在浏览器中,this的值指向window对象。在函数指向上下文中,this的值取决于函数的调用方式。如果它被一个对象引用调用,那么this的值被设置为该对象,否则this的值被设置为全局对象或undefined(严格模式下)。

    Ⅱ、LexicalEnvironment(词法环境):

      ES6文档将词法环境定义为:词法环境是一种规范类型,基于ECMAScript代码的词法嵌套结构来定义标识符与特定变量和函数的关联关系(environment record)和可能为空引用(null)的外部词法环境组成。简而言之,词法环境是一个包含标识符变量映射的结构。(这里的标识符表示变量/函数的名称,变量是对实际对象【包含函数类型对象】或原始值的引用)

     在LexicalEnvironment(词法环境)中,有两个部分组成:(1)环境记录(environment record):是存储变量和函数声明的实际位置 (2)对外部环境的引用:意味着它可以访问外部词法环境。

      LexicalEnvironment(词法环境)有两种类型:

        1.全局环境(在全局执行上下文中)是一个没有外部环境的词法环境。全局环境的外部环境引用为null。它拥有一个全局对象(window对象)及其关联的方法和属性(例如数组方法)以及任何用户自定义的全局变量,this的值指向这个全局对象。

        2.函数环境,用户在函数中定义的变量被存储在环境记录中,对外部环境的引用可以是全局,也可以是包含内部函数的外部函数环境。

        注意:对于函数环境而言,环境记录还包含了一个arguments对象,该对象包含了索引和传递给函数的参数之间的映射以及传递给函数的长度(数量)。

      环境记录同样有两种类型:

        1.声明性环境记录:存储变量、函数和参数。一个函数环境包含声明性环境记录。

        2.对象环境记录:用于定义在全局执行上下文中出现的变量和函数的关联。全局环境包含对象环境记录。

    Ⅲ、VariableEnvironmen(变量环境):

      它也是一个词法环境,其EnvironmentRecord包含了由VariableStatements在此执行上下文创建的绑定。它具有上面定义的语法环境的所有属性。与LexicalEnvironment的区别在于前者用于存储函数声明和变量(let和const)绑定,而后者仅用于存储变量(var)绑定。

    结合实例分析:

        let a=10;
const b=20;
var c;
function addFun (e,f){
var g =50;
return e*f*g;
}
c = addFun(30,40) /*GlobalExecutionContext = {
ThisBinding = <Global Object> //确定this
LexicalEnvironment = {
EnvironmentRecord:{
Type:'Object' //全局环境
//标识符绑定
a:<uninitialized>,
b:<uninitialized>,
addFun:<Func>
},
outer:<null> //对外部环境的引用
}, //词法环境
VariableEnvironment = {
EnvironmentRecord:{
Type:'Object' //全局环境
//标识符绑定
c:undefined
},
outer:<null> //对外部环境的引用
} //变量环境
}
FunctionExecutionContext = {
ThisBinding = <Global Object> //确定this
LexicalEnvironment = {
EnvironmentRecord:{
Type:'Declarative' //函数环境
//标识符绑定
Arguments:{0:30,1:40,length:2}
},
outer:<GlobalLexicalEnvironment>//对外部环境的引用
}, //词法环境
VariableEnvironment = {
EnvironmentRecord:{
Type:'Declarative' //函数环境
//标识符绑定
g:undefined
},
outer:<GlobalLexicalEnvironment>//对外部环境的引用
} //变量环境
}*/

  只有在addFun调用的时候才会创建函数执行上下文。创建之初,代码会被扫描并解析变量和函数声明,其中函数声明存储在环境之中,而变量会被设置为undefined(在var情况下)或保持未初始化(在let和const情况下)。这也是为什么可以在声明之前访问var定义的变量(尽管是undefined),但如果在let或const之前访问定义的变量会提示引用错误的原因。

  这就是所谓的变量提升。

  函数上下文

  在函数上下文中,用活动对象(activation object,AO)来表示变量对象。

  活动对象和变量对象的区别在于:

    1.变量对象(VO)是规范上或者是JS引擎上实现的,并不能在JS环境中直接访问。

    2.当进入到一个执行上下文后,这个变量才会被激活,所以叫活动变量(AO),这个时候活动变量上的各种属性才能被访问。

  调用函数的时候,会为其创建一个Arguments对象,并自动初始化局部变量arguments,指代该Arguments对象。所有作为参数传入的值都会成为Arguments对象的数组元素。

  二、执行阶段分为两个阶段。注:在执行阶段,如果JavaScript引擎在源代码中声明的位置找不到let变量的值,那么将为其分配undefined的值。

    Ⅰ、进入执行阶段

      此时的变量对象会进行初始化:

        1.函数的所有形参:没有实参,属性值设为undefined。

        2.函数声明:如果变量对象已经存在相同的属性,则完全替换这个属性。

        3.变量声明:如果变量名称跟已经声明的形参或函数相同,则变量声明不会干扰已经存在的属性。

    Ⅱ、代码执行

      这个阶段会顺序执行代码,修改变量对象的值。

  执行阶段总结:

    1.全局上下文的变量初始化是全局对象;

    2.函数上下文的变量对象初始化只包括Arguments对象;

    3.在进入执行上下文时会给变量对象添加形参,函数声明,变量声明等初始属性值

    4.在代码执行阶段,会再次修改变量对象的属性值。

Javascript执行上下文和执行栈的更多相关文章

  1. 深入理解 JavaScript 执行上下文和执行栈

    前言 如果你是一名 JavaScript 开发者,或者想要成为一名 JavaScript 开发者,那么你必须知道 JavaScript 程序内部的执行机制.执行上下文和执行栈是 JavaScript ...

  2. 转:JS高级学习笔记(8)- JavaScript执行上下文和执行栈

    必看参考: 请移步:博客园 JavaScript的执行上下文 深入理解JavaScript执行上下文和执行栈 JavaScript 深入之执行上下文 写在开头 入坑前端已经 13 个月了,不能再称自己 ...

  3. 理解 Javascript 执行上下文和执行栈

    如果你是一名 JavaScript 开发者,或者想要成为一名 JavaScript 开发者,那么你必须知道 JavaScript 程序内部的执行机制.理解执行上下文和执行栈同样有助于理解其他的 Jav ...

  4. JavaScript进阶之执行上下文和执行栈

    js引擎的执行过程 执行上下文和执行栈属于js引擎的执行过程的预编译阶段. 执行上下文(Execution Context) 执行上下文是当前 JavaScript 代码被解析和执行时所在环境的抽象概 ...

  5. js执行上下文和执行栈

    执行上下文就是JavaScript 在被解析和运行时环境的抽象概念,JavaScript 运行任何代码都是在执行上下文环境中运行的,执行上下文包括三个周期:创建——运行——销毁,重点说一下创建环节. ...

  6. 【进阶1-1期】理解JavaScript 中的执行上下文和执行栈(转)

    这是我在公众号(高级前端进阶)看到的文章,现在做笔记 https://mp.weixin.qq.com/s/tNl5B4uGdMkJ2bNdbbo82g 阅读笔记 执行上下文是当前 JavaScrip ...

  7. JavaScript 中的执行上下文和执行栈

    JavaScript - 原理系列 ​ 在日常开发中,每当我们接手一个现有项目后,我们总喜欢先去看看别人写的代码.每当我们看到别人写出很酷的代码的时候,我们总会感慨!写出这么优美而又简洁的代码的兄弟到 ...

  8. javascript执行上下文和变量对象

    执行上下文(execution context): 执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念. js语言是一段一段的顺序执行,这个“段”其实就是我们说的这个执行上 ...

  9. Js 执行上下文和作用域

    1.执行上下文和执行栈 执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JavaScript 中运行任何的代码都是在执行上下文中运行. 执行上下文的生命周期包括三个阶 ...

随机推荐

  1. UOJ14 UER #1 DZY Loves Graph(最小生成树+并查集)

    显然可以用可持久化并查集实现.考虑更简单的做法.如果没有撤销操作,用带撤销并查集暴力模拟即可,复杂度显然可以均摊.加上撤销操作,删除操作的复杂度不再能均摊,但注意到我们在删除时就可以知道他会不会被撤销 ...

  2. JSP/JSF从web.xml中取出context-param的配置信息

    JSP/JSF从web.xml中取出context-param的配置信息. 应用场景:我们配置了项目的版本信息,想让他显示在页面上,如: <context-param><!-- ## ...

  3. 搭建Linux下的SVN服务器

    ______________________________________________配置SVN步骤______________________________________________ ...

  4. UOJ#449. 【集训队作业2018】喂鸽子(期望dp)

    题意 有 \(n\) 只鸽子,每只鸽子需要 \(k\) 粒玉米才能喂饱.问每次随意喂给 \(n\) 个鸽子中的一个,期望多久所有鸽子都被喂饱. 对于 \(998244353\) 取模. 数据范围 \( ...

  5. Python3 找不到库

    import sys sys.path.append('/usr/local/lib64/python3.6/site-packages')sys.path.append('/usr/local/li ...

  6. 题解 P4783 【【模板】矩阵求逆】

    题目大意 求一个N×N的矩阵的逆矩阵.答案对10^9+7取模.N<=400 前置知识 矩阵的初等变换 矩阵的逆定义为 A*B=E(E为单位矩阵)此时B为A的逆 思路 如果矩阵有逆 那么这个矩阵经 ...

  7. python中的sequence(序列)

    摘要 这篇文章主要是为了让自己记住字典不是序列,python中序列的类型 序列化的定义 有个朋友问我,什么是序列化,我瞬间懵了,然后查了一下,发现廖雪峰老师给出了一个很舒服的解释: 序列化:我们把变量 ...

  8. 【CH2401】送礼物

    题目大意:NPC 子集和问题. 题解:先搜索一半的物品重量和,记录在一个数组中,并将该数组排序并去重.再搜索另一半物品,到达目标状态后,在前一半物品记录的重量中查找小于当前剩余重量的最大值,更新答案即 ...

  9. DataReader转Dictionary数据类型之妙用

    datareader转dictionary有很多用处,可以输出表中部分字段转实体字段,以前需要全部字段输出或者再建一个实体模型才行,这样就可以减少数据库的输出量了,特别是某些接口的格式化输出很方便. ...

  10. (二分查找 拓展) leetcode 162. Find Peak Element && lintcode 75. Find Peak Element

    A peak element is an element that is greater than its neighbors. Given an input array nums, where nu ...