当前位置: 首页 > news >正文

「JavaScript深入」一文说明白JS的执行上下文与作用域

JavaScript深入 — 执行上下文与作用域

    • 上下文
    • 执行上下文
      • 生命周期
        • 创建阶段
        • 执行阶段
        • 回收阶段
    • 执行栈
    • 作用域链
    • 作用域
      • 词法作用域(静态作用域)


上下文

变量或函数的上下文决定了它们可以访问哪些数据,以及它们的行为。 每个上下文都有一个关联的变量对象,而这个上下文中定义的所有变量和函数都存在于这个对象上。

全局上下文是最外层的上下文,(在浏览器中,全局上下文就是我们常说的 window 对象,因此所有通过 var 定义的全局变量和函数都会成为 window 对象的属性和方法)上下文在其所有代码都执行完毕后会被销毁,包括它上面的变量和函数。

每个函数调用都有自己的上下文。当代码执行流入函数时,函数的上下文被推到一个上下文栈上。在函数执行完之后,上下文栈会弹出该函数的上下文,将控制权返回给之前的执行上下文。


执行上下文

简单的来说,执行上下文是一种对JavaScript代码执行环境的抽象概念,也就是说,只要有JavaScript代码运行,那么它就一定是运行在执行上下文中,变量或函数的上下文决定了它们可以访问哪些数据,以及它们的行为。

执行上下文的类型分为三种:

  • 全局执行上下文:只有一个,浏览器中的全局对象就是 window 对象,this 指向这个全局对象
  • 函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文
  • Eval 函数执行上下文:指的是运行在 eval 函数中的代码,很少用而且不建议使用

🌰 简单举例如下:

在这里插入图片描述

紫色框住的部分为全局上下文,蓝色和橘色框起来的是不同的函数上下文。只有全局上下文(的变量)能被其他任何上下文访问

可以有任意多个函数上下文,每次调用函数创建一个新的上下文,会创建一个私有作用域,函数内部声明的任何变量都不能在当前函数作用域外部直接访问

生命周期

执行上下文的生命周期包括三个阶段:创建阶段->执行阶段->回收阶段

创建阶段

创建阶段即当函数被调用,但未执行任何内部代码之前

  • 确定 this 的值,也被称为 This Binding
  • 词法环境(LexicalEnvironment)组件被创建
  • 变量环境(VariableEnvironment)组件被创建
// 伪代码
ExecutionContext = {ThisBinding = <this value>,LexicalEnvironment = { ... },VariableEnvironment = { ... },
}

This Binding
this 的值是在执行时候才能确认,定义时不能确认

词法环境
词法环境有两个组成部分:

  • 全局环境:是一个没有外部环境的词法环境,其外部环境引用为 null,有一个全局对象,this 的值指向这个全局对象
  • 函数环境:用户在函数中定义的变量被存储在环境记录中,包含了 arguments 对象,外部环境的引用可以是全局环境,也可以是包含内部函数的外部函数环境
// 伪代码
GlobalExectionContext = {    // 全局执行上下文LexicalEnvironment: {      // 词法环境EnvironmentRecord: {     // 环境记录Type: "Object",        // 全局环境// 标识符绑定在这里 outer: <null>          // 对外部环境的引用}  }
}
FunctionExectionContext = { // 函数执行上下文LexicalEnvironment: {     // 词法环境EnvironmentRecord: {    // 环境记录Type: "Declarative",  // 函数环境// 标识符绑定在这里      outer: <Global or outer function environment reference>  // 对外部环境的引用}  }
}

变量环境
变量环境也是一个词法环境,因此它具有上面定义的词法环境的所有属性

在ES6中,词法环境和变量环境的区别在于前者用于存储函数声明和变量(letconst )绑定,而后者仅用于存储变量(var)绑定

执行阶段

在这阶段,执行变量赋值、代码执行

如果JavaScript引擎在源代码中声明的实际位置找不到变量的值,那么将为其分配undefined

回收阶段

执行上下文出栈等待虚拟机回收执行上下文


执行栈

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

在这里插入图片描述

当Javascript引擎开始执行你第一行脚本代码的时候,它就会创建一个全局执行上下文然后将它压到执行栈中

每当引擎碰到一个函数的时候,它就会创建一个函数执行上下文,然后将这个执行上下文压到执行栈中

引擎会执行位于执行栈栈顶的执行上下文(一般是函数执行上下文),当该函数执行结束后,对应的执行上下文就会被弹出,然后控制流程到达执行栈的下一个执行上下文

🌰 举个例子:

let a = 'Hello World!';
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');

🫱 输出结果:

Inside first function
Inside second function
Again inside first function
Inside Global Execution Context

👇 执行栈中内容用图表示:

在这里插入图片描述


作用域链

上下文中的代码在执行时,会创建变量对象的一个作用域链。这个作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。

执行上下文的角度来说: 作用域链是由当前执行上下文和所有外层执行上下文的变量对象组成的链式结构。当JavaScript代码在一个执行上下文中查找变量时,会先在当前执行上下文的变量对象中查找,如果没有找到,就会继续在外层执行上下文的变量对象中查找,直到找到该变量或者到达全局执行上下文。

如果上下文是函数,则其活动对象用作变量对象,活动对象最初只有一个定义变量:arguments

代码正在执行的上下文的变量对象始终位于作用域链的最前端,全局上下文的变量对象始终是作用域链的最后一个变量对象。

var color = "blue";function changeColor() {if(color === "blue"){color = "red";} else {color = "blue";}
}

👆 如上例子,函数 changeColor() 的作用域链包含两个对象:一个是它自己的变量(定义了 arguments 对象),另一个是全局上下文的变量对象。

在这里插入图片描述

上图矩形表示不同的上下文。内部上下文可以通过作用域链访问外部上下文中的一切。

上下文之间的连接是线性的,有序的。每个上下文都可以到上一级上下文中去搜索变量和函数。

在这里插入图片描述

函数执行完毕后,局部活动对象会被销毁,内存中就只剩下全局作用域。


作用域

作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。——《你不知道的JavaScript》

词法作用域(静态作用域)

作用域共有两种工作模型。第一种是最为普遍的,被大多数编程语言所采用的词法作用域,意味着作用域是由书写代码时函数声明的位置来决定的编译时就基本能够知道全部标识符在哪里以及是如何声明的,从而能够在执行过程中对它们进行查找。

var value = 1;function foo() {console.log(value);
}
function bar() {var value = 2;foo();
}bar(); // 1
// 在函数定义的时候确定的作用value等于1 所以调用的时候也等于1 

另一种叫作动态作用域,最常见的就是Bash脚本。

#test.sh
name='lily';function getName() {echo name: $name;
}function getMyName() {local name='lucy';getName;
}getMyName;

如上代码,如果是静态作用域,函数的作用域在定义时就确定了,输出应为“lily”,而Bash是动态作用域,所以其实输出的是“lucy”。

相关文章:

「JavaScript深入」一文说明白JS的执行上下文与作用域

JavaScript深入 — 执行上下文与作用域 上下文执行上下文生命周期创建阶段执行阶段回收阶段 执行栈作用域链作用域词法作用域&#xff08;静态作用域&#xff09; 上下文 变量或函数的上下文决定了它们可以访问哪些数据&#xff0c;以及它们的行为。 每个上下文都有一个关联的…...

Qt C++设计模式->组合模式

组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设计模式&#xff0c;允许你将对象组合成树形结构以表示部分与整体的层次关系。组合模式使得客户端可以以统一的方式对待单个对象和组合对象&#xff0c;简化了对复杂树形结构的操作。 组合模式的应用场景 组合…...

Acwing Bellman-Ford SPFA

1. Bellman-Ford 该算法适用于有负权边的情况&#xff0c;注意&#xff1a;如果有负权环的话&#xff0c;最短路就不一定存在了。时间复杂度 O ( m n ) . O(mn). O(mn).该算法可以求出来图中是否存在负权回路&#xff0c;但求解负权回路&#xff0c;通常用SPFA算法&#xff0c…...

我能禁止使用某协议的ip禁止访问我的资源吗

是的&#xff0c;你可以禁止使用某个协议的IP地址访问你的资源。这种操作通常涉及网络防火墙、服务器配置或应用程序设置&#xff0c;具体方法取决于你的网络环境和使用的技术。以下是一些常见的实现方法&#xff1a; 1. 使用防火墙 大多数防火墙&#xff08;硬件或软件&…...

快速理解TCP协议(二)——TCP协议中的拥塞控制机制详解

在计算机网络中&#xff0c;TCP&#xff08;传输控制协议&#xff09;是一种广泛使用的面向连接的、可靠的、基于字节流的传输层通信协议。TCP协议通过一系列复杂的机制来确保数据的可靠传输&#xff0c;其中拥塞控制是至关重要的一环。本文将深入探讨TCP协议中的拥塞控制机制&…...

Linux:debug: systemtap: ubacktrace

https://docs.huihoo.com/systemtap/sourceware.org/systemtap/SystemTap_Beginners_Guide/ustack.html 这个函数可以帮助将user level的backtrace打印出来。 stap -d /bin/ls --ldd \ -e probe process("ls").function("xmalloc") {print_usyms(ubacktra…...

使用AI进行需求分析的案例研究

生成式 AI 的潜在应用场景似乎无穷无尽。虽然这令人兴奋&#xff0c;但也可能让人不知所措。因此&#xff0c;团队在使用这项技术时需要有明确的目标&#xff1a;关键是要明确生成式 AI 在团队工作中能产生哪些实质性影响。 在软件工程中&#xff0c;一个引人注目的应用场景是…...

Python内置的re库

Python内置的re库是专门用于处理正则表达式的标准库。它提供了一系列函数和类&#xff0c;使得在Python程序中可以使用正则表达式进行字符串的搜索、替换、分割等操作。re库的使用非常广泛&#xff0c;几乎任何需要复杂文本处理的场景都可以用到它。 主要函数 1、complie函数…...

毕业设计选题:基于ssm+vue+uniapp的面向企事业单位的项目申报小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…...

jQuery 简介⑤属性操作

九、属性操作 jQuery的属性操作方法一览表 $("selector").val(); // 获取第一个匹配元素的value值(一般用于表单控("selector").val("Hello"); // 设置所有匹配元素的value值为"Hello" $("selector").html();// 获取第一个…...

[Linux] Linux操作系统 进程的状态

标题&#xff1a;[Linux] Linux操作系统 进程的状态 个人主页&#xff1a;水墨不写bug &#xff08;图片来源于网络&#xff09; 目录 一、前置概念的理解 1.并行和并发 2.时间片 3.进程间具有独立性 4.等待的本质 正文开始&#xff1a; 在校的时候&#xff0c;你一定学过《…...

深入解析Python 中的 sortedcontainers 库:高效的排序数据结构

在日常的 Python 编程中&#xff0c;列表&#xff08;list&#xff09;、集合&#xff08;set&#xff09;和字典&#xff08;dict&#xff09;是常用的数据结构。然而&#xff0c;在某些特定的场景下&#xff0c;我们需要对数据进行排序&#xff0c;并且希望在插入、删除或访问…...

什么是服务器日志,日志有什么作用?

前言 服务器日志是指服务器等电脑设备或软件的运作记录‌。这些日志记录了服务器接收客户端处理请求的过程以及服务器对这些请求的处理结果。服务器日志对于排查和解决计算机系统和网络应用中的问题至关重要&#xff0c;因为它们包含了用于调试问题的消息、服务器状态以及其他…...

Codeforces Round 971 (Div. 4)A-G1题解

Codeforces Round 971 (Div. 4) A 就是b - a #include <bits/stdc.h> #define int long longusing namespace std;void solve() {int a, b;cin >> a >> b;cout << b - a << endl; }signed main() {ios::sync_with_stdio(false);cin.tie(0);co…...

QT----基于QML的计时器

赶上了实习的末班车,现在在做QML开发,第一天的学习成果,一个计时器.逻辑挺简单的,纯QML实现,代码在仓库,可以对比文档和提交记录学习起来更清晰 QT-Timer 学习使用c的listmodel 学习使用了如何用c的listmodel来存储数据. 新建一个TImeListModel类继承自QAbstractListModel c…...

Stable Diffusion的高分辨率修复(Hires.fix)

Stable Diffusion的高分辨率修复&#xff08;Hires.fix&#xff09;是一项重要的功能&#xff0c;它旨在提高生成图像的分辨率和细节&#xff0c;从而使画面变得更加清晰和精细。以下是关于Stable Diffusion高分辨率修复&#xff08;Hires.fix&#xff09;的详细解释&#xff1…...

智慧体育馆可视化:实时监控与智能管理

利用图扑可视化技术实现对体育馆的实时监控和数据分析&#xff0c;提升运营效率、观众体验和安全管理水平&#xff0c;打造智能化场馆环境。...

【NLP】基于“检测器-纠错器”中文文本纠错框架

前言 许多方法将中文拼写纠正&#xff08;检测和纠正给定中文句子中的错误字符&#xff09;视为序列标注任务&#xff0c;并在句子对上进行微调。一些方法使用错误检测器作为初步任务&#xff0c;然后将检测结果用于辅助后续的错误纠正过程。然而&#xff0c;现有方法在使用检…...

vue 中加载 Mapbox GL JS Examples

Mapbox GL JS 示例 1. Mapbox GL JS的基础使用2. style 的使用2.1. 切换 style2.2. 配置一个第三方 style &#xff08;添加一个Layer&#xff09;2.3. 配置一个带有 slot 的 style2.4. 创建一个自定义 style 的 layer 类实现 WebGL 内容2.5. 添加Marker2.6. 添加 geojson 格式…...

Vue3 中组件传递 + css 变量的组合

文章目录 需求效果如下图所示代码逻辑代码参考 需求 开发一个箭头组件&#xff0c;根据父组件传递的 props 来修改 css 的颜色 效果如下图所示 代码逻辑 代码 父组件&#xff1a; <Arrow color"red" />子组件&#xff1a; <template><div class&…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案

在移动互联网营销竞争白热化的当下&#xff0c;推客小程序系统凭借其裂变传播、精准营销等特性&#xff0c;成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径&#xff0c;助力开发者打造具有市场竞争力的营销工具。​ 一、系统核心功能架构&…...

uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略&#xff08;地理位置/文件&#xff09; 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型&#xff0c;核心实现方式&#xff1a; 标准消息类型&#xff1a;直接使用 SDK 内置类型&#xff08;文件、图片等&#xff09;自…...

Xela矩阵三轴触觉传感器的工作原理解析与应用场景

Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知&#xff0c;帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量&#xff0c;能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度&#xff0c;还为机器人、医疗设备和制造业的智…...

【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权

摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题&#xff1a;安全。文章将详细阐述认证&#xff08;Authentication) 与授权&#xff08;Authorization的核心概念&#xff0c;对比传统 Session-Cookie 与现代 JWT&#xff08;JS…...

无头浏览器技术:Python爬虫如何精准模拟搜索点击

1. 无头浏览器技术概述 1.1 什么是无头浏览器&#xff1f; 无头浏览器是一种没有图形用户界面&#xff08;GUI&#xff09;的浏览器&#xff0c;它通过程序控制浏览器内核&#xff08;如Chromium、Firefox&#xff09;执行页面加载、JavaScript渲染、表单提交等操作。由于不渲…...

汇编语言学习(三)——DoxBox中debug的使用

目录 一、安装DoxBox&#xff0c;并下载汇编工具&#xff08;MASM文件&#xff09; 二、debug是什么 三、debug中的命令 一、安装DoxBox&#xff0c;并下载汇编工具&#xff08;MASM文件&#xff09; 链接&#xff1a; https://pan.baidu.com/s/1IbyJj-JIkl_oMOJmkKiaGQ?pw…...