深入理解JS的执行上下文、词法作用域和闭包(上)

在这里插入图片描述

🤍 前端开发工程师、技术日更博主、已过CET6
🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1
🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》
🍚 蓝桥云课签约作者、上架课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入门到实战全面掌握 uni-app》

文章目录

  • 摘要
  • 引言
  • 一、执行上下文 🌳
    • 执行上下文的定义和作用
    • 栈结构与执行上下文的关系 💻
  • 二、词法作用域 🌏
    • 词法作用域的基本原理
    • 变量的可见性和作用域链 🔍
    • 如何利用词法作用域进行代码封装 📦

摘要

本文将深入探讨执行上下文、词法作用域和闭包的概念📝,帮助读者更好地理解这些关键的编程概念。通过具体示例和详细讲解,我们将揭示它们在 JavaScript 中的工作原理和应用场景。

引言

在 JavaScript 编程中,执行上下文、词法作用域和闭包是非常重要的概念🎯。理解它们对于编写高效、可靠的代码至关重要。在本文中,我们将一起探索这些概念的本质,以及它们如何影响代码的执行和行为。

一、执行上下文 🌳

执行上下文的定义和作用

在JavaScript中,执行上下文(Execution Context)是ECMAScript规范中的一个概念,它定义了代码执行时的环境。JavaScript中的执行上下文分为两种:全局执行上下文和函数执行上下文。

  1. 全局执行上下文:

全局执行上下文是JavaScript程序的根上下文,当一个程序开始执行时,它会首先进入全局执行上下文。在全局执行上下文中,会创建全局对象(global object),它是全局变量的宿主,同时还会创建一个名为"this"的变量,指向全局对象。在全局执行上下文中,JavaScript会执行全局代码,直到遇到一个函数调用。

作用:

  • 创建全局对象:在全局执行上下文中,会创建全局对象,它是全局变量的宿主。
  • 创建"this"变量:在全局执行上下文中,会创建一个名为"this"的变量,指向全局对象。
  • 执行全局代码:在全局执行上下文中,JavaScript会执行全局代码,直到遇到一个函数调用。
  1. 函数执行上下文:

当在全局执行上下文中遇到一个函数调用时,会进入函数执行上下文。在函数执行上下文中,会创建一个活动对象(activation object),它是函数局部变量的宿主,同时还会创建一个名为"this"的变量,指向函数的上下文(即调用该函数的对象)。在函数执行上下文中,JavaScript会执行函数体中的代码,直到函数执行完毕。

作用:

  • 创建活动对象:在函数执行上下文中,会创建一个活动对象,它是函数局部变量的宿主。
  • 创建"this"变量:在函数执行上下文中,会创建一个名为"this"的变量,指向函数的上下文(即调用该函数的对象)。
  • 执行函数体中的代码:在函数执行上下文中,JavaScript会执行函数体中的代码,直到函数执行完毕。

总结:执行上下文是JavaScript代码执行时的环境,它定义了代码执行时的上下文状态和规则。通过理解执行上下文,可以更好地理解JavaScript中的变量作用域、函数调用和"this"指向等问题。

栈结构与执行上下文的关系 💻

栈结构(Stack)是一种后进先出(LIFO)的数据结构,用于存储和管理执行上下文。在JavaScript中,栈结构用于存储和管理函数执行上下文。

当JavaScript遇到一个函数调用时,它会将该函数的执行上下文压入栈中,成为当前执行上下文。然后,在该函数体中执行代码,直到函数执行完毕。当函数执行完毕后,它会将该函数的执行上下文弹出栈,恢复之前的执行上下文。

例如,以下代码:

function foo() {console.log('foo');bar();
}function bar() {console.log('bar');
}foo();

执行过程如下:

  1. 执行全局代码,遇到函数调用foo()
  2. foo函数的执行上下文压入栈中,成为当前执行上下文。
  3. foo函数体中执行代码,遇到函数调用bar()
  4. bar函数的执行上下文压入栈中,成为当前执行上下文。
  5. bar函数体中执行代码,执行完毕。
  6. bar函数的执行上下文弹出栈,恢复之前的执行上下文(即foo函数的执行上下文)。
  7. foo函数继续执行,执行完毕。
  8. foo函数的执行上下文弹出栈,恢复全局执行上下文。

总结:栈结构用于存储和管理函数执行上下文,它与执行上下文之间的关系是:栈结构中的每个元素都是一个函数的执行上下文,而执行上下文是指代码执行时的环境。通过理解栈结构与执行上下文之间的关系,可以更好地理解JavaScript中的函数调用和执行顺序等问题。

二、词法作用域 🌏

词法作用域的基本原理

词法作用域(Lexical Scope)是指由代码文本中变量声明的位置决定的变量可访问的范围。在JavaScript中,词法作用域主要受到函数和块级作用域(如letconst声明的变量)的影响。

词法作用域的基本原理可以概括为以下几点:

  1. 函数内的变量声明对外部不可见:在函数内部声明的变量只能在函数内部访问,无法被外部访问。

例如:

function foo() {let a = 1;console.log(a); // 输出 1
}console.log(a); // 报错:a is not defined
  1. 块级作用域内的变量声明对嵌套函数不可见:在letconst声明的变量所在的块级作用域内,嵌套的函数无法访问这些变量。

例如:

function foo() {let a = 1;if (true) {let b = 2;console.log(a); // 输出 1console.log(b); // 输出 2}console.log(b); // 报错:b is not defined
}
  1. 函数内的变量声明不会覆盖外部的变量:在函数内部声明的变量与同名的外部变量不会互相影响。

例如:

let a = 1;function foo() {let a = 2;console.log(a); // 输出 2
}console.log(a); // 输出 1
  1. 函数内的变量声明不会影响全局变量:在函数内部声明的变量不会影响到全局变量。

例如:

let a = 1;function foo() {let a = 2;console.log(a); // 输出 2
}console.log(a); // 输出 1

总之,词法作用域是由代码文本中变量声明的位置决定的变量可访问的范围。在JavaScript中,词法作用域主要受到函数和块级作用域的影响。理解词法作用域的基本原理有助于更好地理解JavaScript中的变量作用域和函数调用等问题。

变量的可见性和作用域链 🔍

在JavaScript中,变量的可见性和作用域链是理解变量可访问范围和作用域问题的关键。下面是对这两个概念的解释:

  1. 变量的可见性:

变量的可见性是指在代码中可以访问到某个变量的范围。在JavaScript中,变量的可见性受到词法作用域和动态作用域的影响。

词法作用域是由代码文本中变量声明的位置决定的,它决定了哪些变量可以在哪些代码块中访问。动态作用域是由函数调用和变量赋值等操作形成的,它决定了函数内部的变量可以被外部访问。

例如:

function foo() {let a = 1;console.log(a); // 输出 1
}console.log(a); // 报错:a is not defined

在这个例子中,变量a在函数foo内部声明,它的可见性受到词法作用域的影响,因此只能在foo函数内部访问,在外部访问会报错。

  1. 作用域链:

作用域链是指当一个变量在当前作用域中找不到定义时,JavaScript会依次向上级作用域查找,直到找到该变量或到达全局作用域。作用域链的查找顺序是由变量声明的位置决定的。

例如:

let a = 1;function foo() {let b = a;console.log(b); // 输出 1
}console.log(b); // 报错:b is not defined

在这个例子中,变量b在函数foo内部声明,它的作用域链包括函数foo和全局作用域。由于b在函数foo内部找不到定义,所以会向全局作用域查找,找到变量a,因此b的值为1

总结:变量的可见性和作用域链是理解JavaScript中变量作用域和函数调用等问题的重要概念。实际项目中,可以根据变量的声明位置和作用域链的规则,灵活地管理和访问变量。

如何利用词法作用域进行代码封装 📦

词法作用域是JavaScript中一种重要的作用域类型,它由代码文本中变量声明的位置决定。利用词法作用域进行代码封装可以有效地提高代码的可维护性和可读性。下面介绍几种利用词法作用域进行代码封装的方法:

  1. 使用函数封装:

将一组相关的变量和函数封装在一个函数内部,可以避免全局作用域的污染,提高代码的可维护性。

例如,将一个购物车相关的数据和操作封装在一个函数内部:

function createCart() {let products = [];function addProduct(product) {products.push(product);}function getProducts() {return products;}return {addProduct,getProducts};
}const cart = createCart();
cart.addProduct({ id: 1, name: 'Product 1' });
console.log(cart.getProducts()); // 输出:[{ id: 1, name: 'Product 1' }]

在这个例子中,productsaddProductgetProducts函数被封装在createCart函数内部,外部代码无法直接访问这些变量和函数,只能通过createCart函数返回的接口进行访问。

  1. 使用块级作用域封装:

利用letconst声明的变量具有块级作用域的特性,可以将一组相关的变量封装在一个代码块内部。

例如,将一个用户相关的数据和操作封装在一个if语句块内部:

let user = null;if (isLoggedIn) {user = {id: 1,name: 'User 1'};function getUserName() {return user.name;}
}console.log(getUserName()); // 输出:User 1

在这个例子中,usergetUserName函数被封装在if语句块内部,当isLoggedIntrue时,这些变量和函数才会被创建。

总之,利用词法作用域进行代码封装是一种有效的编程方法,可以提高代码的可维护性和可读性。实际项目中,可以根据具体需求和场景,灵活地使用函数封装和块级作用域封装等方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2807356.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

ARM Cortex-X5 传言表现不佳,高功率浪涌和低多核分数影响即将推出的核心设计

ARM 的新 Cortex-X5 设计似乎遇到了问题,有新的传言称,超级核心在提高时钟速度时会经历严重的高功耗,并且当最大功率限制降低时,多核性能会下降。虽然这对高通来说可能不是问题,因为据说其 Snapdragon 8 Gen 4 采用定制…

华为HCIP Datacom H12-831 卷24

多选题 1、如图所示,某园区部署OSPF实现网络互通,其中Area1部署为NSSA区域。某工程师为了实现R1访问R4的环回口地址,在R4的OSPF进程中引入直连路由。以下关于该场景的描述,错误的有哪些项? A、在R4引入直连路由后,R1通过转换后的…

服务区智慧公厕

在如今追求智能化、便捷化的社会背景下,高速公路服务区智慧公厕正成为人们关注的焦点。作为高速公路上的必要设施,公厕的提升已经不再局限于简单的清洁卫生,而是更多地涉及到智能化、舒适度和用户体验。本文以智慧公厕源头厂家广州中期科技有…

华为---RSTP(三)---P/A机制及RSTP的生成树形成过程

目录 1. P/A机制简介 1.1 P/A机制的作用 1.2 P/A协商的前提条件 1.3 RSTP选举思路 2. P/A协商过程 3. 举例说明RSTP的生成树形成过程 3.1 示例环境要求 3.2 RSTP的生成树形成过程 3.2.1 SW和SW1之间链路上抓包分析 3.2.2 SW和SW2之间链路上抓包分析 3.2.3 SW1和SW2之…

CSS重点知识整理1

目录 1 平面位移 1.1 基本使用 1.2 单独方向的位移 1.3 使用平面位移实现绝对位置居中 2 平面旋转 2.1 基本使用 2.2 圆点转换 2.3 多重转换 3 平面缩放 3.1 基本使用 3.2 渐变的使用 4 空间转换 4.1 空间位移 4.1.1 基本使用 4.1.2 透视 4.2 空间旋转 4.3 立…

Type-C连接器笔记

一、Type-C的介绍 Type-C是一种全新的USB接口形式,由USB Implementers Forum(USB-IF)制定,并在2014年获得苹果、谷歌、英特尔、微软等厂商支持后开始普及。它是一种通用串行总线(USB)的硬件接口规范&#x…

Stable Diffusion 3 发布及其重大改进

1. 引言 就在 OpenAI 发布可以生成令人瞠目的视频的 Sora 和谷歌披露支持多达 150 万个Token上下文的 Gemini 1.5 的几天后,Stability AI 最近展示了 Stable Diffusion 3 的预览版。 闲话少说,我们快来看看吧! 2. 什么是Stable Diffusion…

React18源码: Fiber树中的全局状态与双缓冲

Fiber树构造 在React运行时中,fiber树构造位于 react-reconciler 包在正式解读 fiber 树构造之前,再次回顾一下renconciler的4个阶段 1.输入阶段:衔接react-dom包,承接fiber更新请求2.注册调度任务:与调度中心(schedu…

JavaScript+PHP实现视频文件分片上传

摘要 视频文件分片上传,整体思路是利用JavaScript将文件切片,然后循环调用上传接口 upload.php 将切片上传到服务器。这样将由原来的一个大文件上传变为多个小文件同时上传,节省了上传时间,这就是文件分片上传的其中一个好处。 上…

STL容器之list

​ 1.封装除了对数据的保护、更好地管理数据之外,还有实现了对上层的统一; ​ 2.类模板参数的不同,一方面是为了实例化出来不同的类,另一方面是为了实现类的成员函数的不同; 一、认识list ​ 1.list是一种带头双向循…

Qt的QFileSystemModel与QTreeView、QTableView、QListView的组合使用

1.相关描述 QFileSystemModel与QTreeView、QTableView、QListView的组合,当QTreeView点击发生改变,QTableView和QListView也会发生变化 2.相关界面 3.相关代码 mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h"…

Python is not set from command line or npm configuration 报错解决

问题 在 npm install 的过程中提示 Python is not set from command line or npm configuration 的报错,相信不少朋友都遇到过,出现这个问题的原因是缺少 python 环境所导致的。 解决方法 1、安装 python 官网:https://www.python.org/dow…

[AutoSar]BSW_Com02 PDU详解

目录 关键词平台说明缩写对照表一、PDU的定义和分类1.1定义1.2 分类 缩写对照表 1 关键词 嵌入式、C语言、autosar、OS、BSW 平台说明 项目ValueOSautosar OSautosar厂商vector ,芯片厂商TI 英飞凌编程语言C,C编译器HighTec (GCC) >>>>&g…

逆变器基础认知

引言 这段时间发现有些行业还是比较有意思的,而且有东西可学。 电源:LLC、PFC 逆变:UPS、PCS 电机:BLDC(FOC)、PMSM 电池:电车BMS、储能 所以会写几篇文章来入门,一是做笔记总结&am…

docker打包当前dinky项目

以下是我的打包过程&#xff0c;大家可以借鉴。我也是第一次慢慢摸索&#xff0c;打包一个公共项目&#xff0c;自己上传。 如果嫌麻烦&#xff0c;可以直接使用我的镜像&#xff0c;直接跳到拉取镜像&#xff01; <可以在任何地方的服务器进行拉取> docker打包当前din…

1_怎么看原理图之GPIO和门电路笔记

一、GPIO类 如下图&#xff1a;芯片输出高电平/3.3V&#xff0c;LED亮&#xff1b;当芯片输出低电平&#xff0c;则LED暗 如下图&#xff1a;输入引脚&#xff0c;当开关闭合&#xff0c;则输入为低电平/0V&#xff0c;当开关打开&#xff0c;则输入为高电平/3.3V 现在的引脚都…

一个更好的IP工具箱MyIP

什么是 MyIP &#xff1f; MyIP 是一个完全开源的 IP 信息查看器&#xff0c;可以轻松检查你的 IP&#xff0c;IP 地理位置&#xff0c;检查 DNS 泄漏&#xff0c;检查 WebRTC 连接&#xff0c;速度测试&#xff0c;ping 测试&#xff0c;MTR 测试&#xff0c;检查网站可用性等…

【Ubuntu】通过网线连接两台电脑以实现局域网连接的方法

有时我们需要将多台计算机连接在一起&#xff0c;以便实现数据共享、资源访问等功能。本文将介绍如何通过网线连接两台运行Ubuntu操作系统的电脑&#xff0c;以便它们能够直接通信&#xff0c;从而实现局域网连接。 1. 准备工作 在开始之前&#xff0c;请准备好&#xff1a; …

一周学会Django5 Python Web开发-Django5二进制文件下载响应

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计25条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

C# EF Core迁移数据库

现象&#xff1a; 在CodeFirst时&#xff0c;先写字段与表&#xff0c;创建数据库后&#xff0c;再添加内容 但字段与表会变更&#xff0c;比如改名删除增加等 需求&#xff1a; 当表字段变更时&#xff0c;同时变更数据库&#xff0c;执行数据库迁移 核心命令 Add-Migrat…