JavaScript中的执行上下文,既然遇见了这篇图文并茂的文章,干脆看完吧!(系列四)

本文主要是介绍JavaScript中的执行上下文,既然遇见了这篇图文并茂的文章,干脆看完吧!(系列四),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

JavaScript中的执行上下文

JavaScript基础提升合集

🚀包含this、call、原型链、作用域等基础经典知识点
☕️每周一篇,打好基础,爬升不累
💬最全知识点解析,易懂的代码示例收藏方便阅读
💻完整版在线阅读,猛戳这里~

目录

  • 前言
  • 一、怎么描述执行上下文?
  • 二、执行栈
  • 三、形象化执行栈
  • 四、思考与总结
  • 五、写在最后

前言

在这里插入图片描述
又到了修炼JavaScript内功的时候了,继上一篇《从作用域到作用域链》之后,我们来谈一谈执行上下文,在写这篇文章的时候总感觉无法完整的将知识点串联起来,所以希望大家也能提些建议哦,让这篇文章更值得收藏、点赞哦~

一、怎么描述执行上下文

1.1 本节知识导图:
在这里插入图片描述

1.2 如果描述执行上下文

  1. 当函数执行时,会创建一个称为执行上下文的内部对象。一个执行上下文定义了一个函数执行时的环境;
  2. 当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方式、传入的参数等信息 ;
  3. 每个函数在被定义时,就会有一个[[scope]]属性,这个属性里保存着作用域链,而执行的前一刻都会创建一个OA对象,这个对象就是执行上下文,这个OA对象会被插入[[scope]]中作用域链的最顶端,这个对象里保存着函数体声明的所有变量、参数和方法。一个OA对象的有序列表。

上述三条描述都符合执行上下文的一些特点,但侧重点都不一样。

1.3 执行上下文的类型

  1. 全局执行上下文:只有一个,浏览器中的全局对象就是 window 对象,this 指向这个全局对象。

  2. 函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文。

  3. Eval 函数执行上下文: 指的是运行在 eval 函数中的代码,很少用而且不建议使用。

在这里插入图片描述

二、执行栈(Execution context stack)

大家都明白,函数的执行顺序和它的定义顺序没关系,但如何解释,就需要从执行栈说起了。

2.1 本节知识导图

在这里插入图片描述

2.2 描述执行栈

执行栈,也叫调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文。

首次运行JS代码时,会创建一个全局执行上下文并Push到当前的执行上下文栈中。每当发生函数调用,引擎都会为该函数创建一个新的函数执行上下文并push到当前执行栈的栈顶。

当栈顶函数运行完成后,其对应的函数执行上下文将会从执行栈中pop出,上下文控制权将移到当前执行栈的下一个执行上下文。

接下来问题来了,我们写的函数多了去了,如何管理创建的那么多执行上下文呢?

三、形象化执行栈

我们利用图片+文字描述的方式来解释这样几段代码:

3.1 为了模拟执行上下文栈的行为,让我们定义执行上下文栈为一个数组:

var ECStack = [];

试想当 JavaScript 开始要解释执行代码的时候,最先遇到的就是全局代码,所以初始化的时候首先就会向执行上下文栈压入一个全局执行上下文,我们用 globalContext 表示它,并且只有当整个应用程序结束的时候,ECStack 才会被清空,所以程序结束之前, ECStack 最底部永远有个globalContext

ECStack.push('globalContext');
ECStack // ["globalContext"]

现在 JavaScript 遇到下面的这段代码了:

function fun1() {fun2();
}
function fun2() {fun3();
}
function fun3() {console.log('最后打印3')
}
fun1(); // 最后打印3

当执行一个函数的时候,就会创建一个执行上下文,并且压入(push)执行上下文栈,当函数执行完毕的时候,就会将函数的执行上下文从栈中弹出(pop)。知道了这样的工作原理,让我们来看看如何处理上面这段代码:

// 伪代码// fun1()
ECStack.push(<fun1> functionContext);// fun1中竟然调用了fun2,还要创建fun2的执行上下文
ECStack.push(<fun2> functionContext);// 擦,fun2还调用了fun3!
ECStack.push(<fun3> functionContext);// fun3执行完毕
ECStack.pop();// fun2执行完毕
ECStack.pop();// fun1执行完毕
ECStack.pop();// javascript接着执行下面的代码,但是ECStack底层永远有个globalContext
注意:除了流程图,在此送大家2020最新企业级 Vue3.0/Js/ES6/TS/React/Node等实战视频教程,点击此处免费获取,小白勿进哦

在这里插入图片描述

再看如下代码:

console.log(1);function father() {console.log(2);(function child() {console.log(3);}());console.log(4);
}
father();console.log(5);
//会依次输出 1 2 3 4 5

分析它的执行栈经历了什么:

在这里插入图片描述
其实到这里我们已经大致了解了执行栈在函数执行前->执行后的流程了,但下一篇文章我们会详细了解释一下,感兴趣的小伙伴不妨点个关注,不跑丢哦~
在这里插入图片描述

四、思考题

现在我们已经了解了执行上下文栈是如何处理执行上下文的,所以让我们看看上篇文章《从作用域到作用域链》最后的问题:

var scope = "global scope";
function checkscope(){var scope = "local scope";function f(){return scope;}return f();
}
checkscope();
var scope = "global scope";
function checkscope(){var scope = "local scope";function f(){return scope;}return f;
}
checkscope()();

两段代码执行的结果一样,但是两段代码究竟有哪些不同呢?

答案就是执行上下文栈的变化不一样。

让我们模拟第一段代码:

ECStack.push(<checkscope> functionContext);
ECStack.push(<f> functionContext);
ECStack.pop();
ECStack.pop();

让我们模拟第二段代码:

ECStack.push(<checkscope> functionContext);
ECStack.pop();
ECStack.push(<f> functionContext);
ECStack.pop();

在这里插入图片描述
如果像上一小结一样画个图的话,两段代码确实很不同哦~

参考

  • 《你不知道的JavaScript》
  • JavaScript深入之执行上下文栈

五、写在最后

JavaScript内功基础部分已经总结到第四篇了,本系列大约会有15篇文章,都是我们在面试最高频的,但工作中常常被忽略的知识点。

热门开源-欢迎star支持

  • 前端进阶
  • 高频经典手撕代码实现
  • 剑指Offer题解
  • LeetCode题解

关于我

  • 花名:余光
  • Writing Vue and JavaScript
  • Working at GaoDing Design
  • A console log tester

如果您看到了最后,不妨收藏、点赞、评论一下吧!!!
持续更新,您的三连就是我最大的动力,虚心接受大佬们的批评和指点,共勉!

这篇关于JavaScript中的执行上下文,既然遇见了这篇图文并茂的文章,干脆看完吧!(系列四)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/379732

相关文章

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt

SpringBoot集成Milvus实现数据增删改查功能

《SpringBoot集成Milvus实现数据增删改查功能》milvus支持的语言比较多,支持python,Java,Go,node等开发语言,本文主要介绍如何使用Java语言,采用springboo... 目录1、Milvus基本概念2、添加maven依赖3、配置yml文件4、创建MilvusClient

浅析Java中如何优雅地处理null值

《浅析Java中如何优雅地处理null值》这篇文章主要为大家详细介绍了如何结合Lambda表达式和Optional,让Java更优雅地处理null值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录场景 1:不为 null 则执行场景 2:不为 null 则返回,为 null 则返回特定值或抛出异常场景

SpringMVC获取请求参数的方法

《SpringMVC获取请求参数的方法》:本文主要介绍SpringMVC获取请求参数的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下... 目录1、通过ServletAPI获取2、通过控制器方法的形参获取请求参数3、@RequestParam4、@

SpringBoot应用中出现的Full GC问题的场景与解决

《SpringBoot应用中出现的FullGC问题的场景与解决》这篇文章主要为大家详细介绍了SpringBoot应用中出现的FullGC问题的场景与解决方法,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录Full GC的原理与触发条件原理触发条件对Spring Boot应用的影响示例代码优化建议结论F

springboot项目中常用的工具类和api详解

《springboot项目中常用的工具类和api详解》在SpringBoot项目中,开发者通常会依赖一些工具类和API来简化开发、提高效率,以下是一些常用的工具类及其典型应用场景,涵盖Spring原生... 目录1. Spring Framework 自带工具类(1) StringUtils(2) Coll

SpringBoot条件注解核心作用与使用场景详解

《SpringBoot条件注解核心作用与使用场景详解》SpringBoot的条件注解为开发者提供了强大的动态配置能力,理解其原理和适用场景是构建灵活、可扩展应用的关键,本文将系统梳理所有常用的条件注... 目录引言一、条件注解的核心机制二、SpringBoot内置条件注解详解1、@ConditionalOn

通过Spring层面进行事务回滚的实现

《通过Spring层面进行事务回滚的实现》本文主要介绍了通过Spring层面进行事务回滚的实现,包括声明式事务和编程式事务,具有一定的参考价值,感兴趣的可以了解一下... 目录声明式事务回滚:1. 基础注解配置2. 指定回滚异常类型3. ​不回滚特殊场景编程式事务回滚:1. ​使用 TransactionT

Spring LDAP目录服务的使用示例

《SpringLDAP目录服务的使用示例》本文主要介绍了SpringLDAP目录服务的使用示例... 目录引言一、Spring LDAP基础二、LdapTemplate详解三、LDAP对象映射四、基本LDAP操作4.1 查询操作4.2 添加操作4.3 修改操作4.4 删除操作五、认证与授权六、高级特性与最佳