JavaScript基础知识强化:变量提升、作用域逻辑及TDZ的全面解析

在这里插入图片描述

🔥 个人主页:空白诗

在这里插入图片描述

文章目录

    • ⭐️ 引言
    • 🎯 变量提升(Hoisting)
      • 👻 暂时性死区(Temporal Dead Zone, TDZ)解释
      • 📦 `var`声明
      • 🔒 `let`与`const`声明
      • 📖 函数声明 与 函数表达式
        • 函数声明
        • 函数表达式
      • 📌 小结
    • 🌐 作用域(Scope)深入探索
      • 🌳 全局作用域
      • 📁 函数作用域
      • 🧱 块级作用域 (`let` & `const`)
      • 📘 词法作用域(Lexical Scoping)
      • 🌀 提升与作用域的相互作用深化理解
    • 💯 总结与巩固
    • 🔗 相关链接

⭐️ 引言

在深入探究JavaScript语言的核心机制时,理解变量提升(Hoisting)和作用域(Scope)的概念是每位开发者不可或缺的基石。这两个基本而又强大的特性,直接影响着我们编写的代码如何被解析和执行。本文旨在通过透彻的解析与实战示例,带你拨开迷雾,清晰地把握变量在JavaScript执行环境中的生命轨迹及可见范围,为构建更加健壮、高效的应用程序打下坚实的基础。让我们一起深入探索,揭开JavaScript变量行为的神秘面纱。

在这里插入图片描述


🎯 变量提升(Hoisting)

「变量提升」JavaScript执行模型的关键特性,它描述了在代码实际执行前,引擎如何处理变量和函数声明的逻辑顺序。这一机制对于深入理解代码执行流程,特别是作用域和变量生命周期管理,具有重要意义。具体细节如下:

👻 暂时性死区(Temporal Dead Zone, TDZ)解释

暂时性死区JavaScript中与letconst声明相关的概念。在变量声明的块或作用域中,从声明点之前直到声明执行完成的这段时间,变量处于TDZ。在这段时间内,尝试访问该变量会触发ReferenceError,即使是在理论上变量已经被提升之后。这种设计旨在避免因变量声明前的不一致状态而导致的难以追踪的错误,增强了代码的可预测性和安全性。

📦 var声明

console.log(a); // 输出:undefined
var a = 10; // 实际上,变量`a`的声明在逻辑上被提升至作用域顶部,而赋值操作保留在原处。
  • 💡 解释:尽管变量a的赋值在打印语句之后,由于var声明的提升特性,使得在声明之前访问a不会引发错误,而是返回undefined

🔒 letconst声明

if (true) {console.log(b); // 报错:ReferenceError,因为访问了TDZ内的变量let b = 5;
}
  • 💭 注记letconst不仅限定了变量的作用域为最近的块级,而且引入了暂时性死区(Temporal Dead Zone, TDZ)的概念。在这个区域内,变量已声明但未初始化,任何访问尝试都会导致ReferenceError,确保了变量在使用前已被正确定义和初始化,提高了代码的健壮性。

📖 函数声明 与 函数表达式

函数声明
sayHello(); // 输出:Hello, World!
function sayHello() {console.log('Hello, World!');
}
  • 😮 亮点:完整的函数声明,包括函数名和函数体,都被提升至所在作用域的顶部,使得函数可以在声明之前被调用。
函数表达式
console.log(greet); // 输出:undefined
var greet = function() {console.log('Greetings!');
};
  • 🧐 注意:虽然变量greet的声明被提升,但赋值操作(函数表达式)并未提升,因此在赋值之前访问greet会得到undefined,而不是引用错误,因为变量在此时已经声明。

📌 小结

在JavaScript中,变量声明是编程的基本构成部分,主要通过varletconst关键字实现,每种声明方式各有特点,特别是在变量提升和作用域规则上表现不同:

  • var声明

    • 作用域:函数作用域或全局作用域。
    • 提升行为:声明(不包括初始化值)被提升到当前作用域顶部,变量默认初始值为undefined
    • 特点:可能导致变量意外覆盖和较弱的封装性。
  • letconst声明

    • 作用域:引入了块级作用域,限制了变量的可见性仅在声明它们的代码块内。
    • 提升行为:存在暂时性死区(Temporal Dead Zone, TDZ),变量在声明之前无法访问,避免了变量声明前的不确定状态。
    • let:允许重新赋值。
    • const:声明常量,一旦赋值后不可更改。
    • 特点:提高了代码的可读性和减少了潜在错误,鼓励更安全的编码习惯。
  • 函数声明与函数表达式

    • 函数声明:整个函数(包括名称和函数体)被提升,可以在声明之前调用。
    • 函数表达式:变量声明被提升,但赋值(即函数定义)保持原位,因此在赋值前访问会得到undefined或引用错误。

理解这些差异并恰当地选择声明方式,对于编写清晰、高效且易于维护的JavaScript代码至关重要。正确的运用变量声明机制,可以有效控制作用域,避免变量污染,提升程序的稳定性和可预测性。


🌐 作用域(Scope)深入探索

🌳 全局作用域

var globalVar = "I'm global";function testScope() {console.log(globalVar); // 输出:I'm global
}
testScope();
  • 🌌 描述:全局作用域中定义的变量在整个程序范围内都可被访问,无论是函数内外。但过度依赖全局变量可能导致命名冲突和数据管理困难。

📁 函数作用域

function scopeExample() {var localVar = "I'm local";console.log(localVar); // 输出:I'm local
}
scopeExample();
console.log(localVar); // 报错:localVar is not defined
  • 🔐 特点:函数作用域意味着变量只在其定义的函数内部有效。这有助于封装和避免变量污染全局空间,提升代码的模块化。

🧱 块级作用域 (let & const)

if (true) {let blockVar = "I'm in a block";console.log(blockVar); // 输出:I'm in a block
}
console.log(blockVar); // 报错:blockVar is not defined
  • 🛡️ 新特性:自ES6起,letconst不仅限定了变量的生命周期于最近的块(如if语句、for循环等)之内,还引入了暂时性死区(TDZ),进一步强化了作用域的概念,减少了变量误用的可能性。

📘 词法作用域(Lexical Scoping)

JavaScript采用词法作用域,这意味着作用域由变量在源代码中的位置决定,而非运行时调用堆栈。这意味着内部函数可以访问外部函数的变量,反之则不行,这为闭包的创建提供了基础。

function outerFunction(outerVariable) {var secret = "I'm a secret!";// 内部函数可以访问外层的变量function innerFunction(innerVariable) {console.log("Inner can access outer:", outerVariable); // 访问外层变量console.log("And knows the secret:", secret); // 也知道秘密变量}return innerFunction;
}// 创建一个innerFunction的实例,但还未执行
var myInnerFunction = outerFunction("Hello from outer");// 当调用myInnerFunction时,它依然记得outerFunction的作用域
myInnerFunction("Hello from inner"); // 控制台输出:
// Inner can access outer: Hello from outer
// And knows the secret: I'm a secret!

解释:在这个例子中,outerFunction定义了一个内部函数innerFunction。尽管outerFunction执行完毕后,按理说其作用域应当销毁,但由于JavaScript的词法作用域特性,innerFunction维持了一个对外部作用域(即outerFunction的作用域)中变量的引用。当innerFunction后来被调用时,它仍然能够访问到outerVariablesecret,尽管这些变量在其定义之外,甚至outerFunction已经执行完毕。这就展示了词法作用域是如何基于代码的静态结构而非运行时调用关系来决定变量访问权限的,同时也是闭包概念的一个经典体现。闭包允许函数维持对其包含作用域中变量的引用,即使在其包含作用域之外执行。


🌀 提升与作用域的相互作用深化理解

  • 变量提升的核心在于变量和函数声明在逻辑上的“提前”,但这并不意味着它们能逃脱作用域的约束。变量的可访问性依然严格遵守其声明时所处的作用域规则,无论是否被提升。

    • var变量提升:尽管变量声明被提升到作用域的顶部,但这并不改变它受当前函数或全局作用域限制的事实。例如,在一个函数内部使用var声明的变量,即便提升后,也仅在该函数内部可访问。
    function example() {console.log(myVar); // 输出:undefinedvar myVar = "I'm here!";
    }
    example();
    console.log(myVar); // 报错:myVar is not defined
    
  • letconst的提升与TDZ:尽管在技术上它们的声明也会在逻辑上先于代码执行前被处理,但JavaScript引擎引入了临时死区(Temporal Dead Zone, TDZ),确保在这些变量真正声明之前,任何访问操作都会失败。这种机制实际上强化了块级作用域的严格性,确保变量在完全初始化之前不可见,从而避免了潜在的未定义行为。

    if (true) {console.log(letVar); // 报错:ReferenceError,因为letVar正处于TDZlet letVar = " Blocked by TDZ";
    }
    

总结而言,提升机制与作用域规则协同工作,确保了JavaScript代码在执行时既遵循了静态的词法作用域原则,又通过TDZ等机制提升了代码的严谨性和可靠性。开发者需清晰理解这些机制,以编写出既高效又健壮的代码。


💯 总结与巩固

  • 变量提升是JavaScript中的一个重要概念,它揭示了变量和函数声明在执行前逻辑上的“提前”,但实际只涉及声明部分。这一特性对变量的可访问性产生了直接影响,尤其是var声明的变量会在其作用域顶部被声明,而letconst虽有提升逻辑,但受临时死区(TDZ)限制,保证了在初始化前不可访问,体现了更加严格的块级作用域规则。

  • 作用域界定了变量存在的上下文环境,确定了变量的生命周期与可访问范围。从全局作用域到函数作用域,再到letconst引入的块级作用域,每个层次都精细控制着变量的可见性。词法作用域的规则确保了变量的访问依据其在代码中的静态位置而非动态执行上下文。

  • 综合应用:掌握变量提升和作用域的规则,是编写高效、健壮JavaScript代码的基石。它们帮助你避免常见的作用域污染、未定义变量访问错误等问题,促进代码的模块化和重用性。通过合理利用作用域隔离变量,可以减少命名冲突,提升代码的可维护性和可读性。

掌握JavaScript变量提升作用域是编程进阶的关键。变量提升涉及声明在执行前逻辑上移至作用域顶部,影响变量初期访问性,尤其注意varletconst的不同行为。作用域划分变量生命周期与可视范围,包括全局、函数、块级,其中词法作用域确保了静态解析,增强代码逻辑性。两者结合,助力构建有序、可维护的代码结构,规避错误,提升开发效率。透彻理解这些机制,是成为JavaScript高手的必经之路。

🔗 相关链接

  • JavaScript 中的 Class 类
  • JavaScript中call、apply与bind的区别
  • JavaScript 垃圾回收机制深度解析:内存管理的艺术
  • 深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
  • 深入理解JavaScript事件循环Event Loop:宏任务与微任务的奇幻之旅
  • JavaScript 防抖与节流——以游戏智慧解锁实战奥秘

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SprintBoot案例-增删改查

黑马程序员JavaWeb开发教程 文章目录 一、准备工作1. 准备数据库表1.1 新建数据库mytlias1.2 新建部门表dept1.3 新建员工表emp 2. 准备一个Springboot工程2.1 新建一个项目 3. 配置文件application.properties中引入mybatis的配置信息,准备对应的实体类3.1 引入myb…

Java类和对象(二)—— 封装,static 关键字与代码块

前言 在面向对象的编程语言中,有三大特性:封装、继承和多态~~ 今天我们就来学习封装的知识 封装 什么是封装 在现实生活中,我们经常使用手机来进行沟通与交流,实际上我们拿到的手机是被封装好的,精美的屏幕&a…

Pencils Protocol Season 2 收官在即,展望Season 3 及其权益

此前 Scroll 生态 LaunchPad &聚合收益平台 Pencils Protocol(原 Penpad),推出了首个资产即其生态代币 PDD 的 Launch,Season 2 活动主要是用户通过质押 ETH 代币、组件战队等方式,来获得 Point 奖励,并…

Go微服务: 日志系统ELK核心架构设计

微服务日志系统建设 1 )为什么需要日志系统 业务发展越来越庞大,服务器越来越多各种访问日志,应用日志,错误日志量越来越多,无法管理开发人员排查问题,需要到服务器上查日志 2 )Elastic Stack…

【MySQL】表的增删改查 | CRUD | 新增 | 查询 | 修改 | 删除 | 数据库约束

文章目录 表的增删改查一、CRUD1.新增(Create)1.插入多行2.指定列多行插入3.插入datetime类型4.插入当前时间5.插入查询的结果 2.查询(Retrieve)1.全列查询 *2.指定列查询3.查询字段为表达式4.指定别名 as5.去重 distinct6.排序 o…

人物介绍模板 PSD 源文件免费获取

免费获取 下载链接在最后! 下载链接在最后! 下载链接在最后! 下载链接在最后! 下载链接在最后! 链接:https://pan.baidu.com/s/1sq3e6djMdZt76Sh_uqVxWg 提取码:naun

WPF之DataGird应用

1,DataGrid相关属性 GridLinesVisibility:DataGrid网格线是否显示或者显示的方式。HorizontalGridLinesBrush:水平网格线画刷。VerticalGridLinesBrush:垂直网格线画刷。HorizontalScrollBarVisibility:水平滚动条可见…

SOLIDWORKS 2024云服务新功能

一、简单的分享一下,在线观看,轻松标记 在达索系统SOLIDWORKS 2024云服务中,您只需在达索系统SOLIDWORKS中点击按钮,就可以将当前的设计分享给其他人,无论是客户、供应商还是团队内部成员。共享的用户只要打开浏览器里…

C++:编程世界的永恒之石

在编程的广袤领域中,C犹如一块永恒的基石,历经岁月的洗礼,依旧坚固而璀璨。它的深厚底蕴、强大功能和广泛的应用领域,使其成为无数程序员心中的信仰与追求。 一、C:历史与传承的交汇点 C的历史可追溯到上世纪80年代&…

详解JS的URL()和URLSearchParams() API接口

两个 API 接口定义 URL() 构造函数返回一个新创建的 URL 对象,表示由一组参数定义的 URL。 URLSearchParams 接口定义了一些实用的方法来处理 URL 的查询字符串。 快速了解两个 API 在哪里用 以前我们要对地址栏中的 URL 地址进行分析处理,需要自己进…

Redis如何避免数据丢失?——AOF

目录 AOF日志 1. 持久化——命令写入到AOF文件 写到用户缓冲区 AOF的触发入口函数——propagate 具体的实现逻辑——feedAppendOnlyFile 从用户缓冲区写入到AOF文件(磁盘) 函数write、fsync、fdatasync Redis的线程池 AOF文件的同步策略 触发的入口函数——…

NSSCTF Web方向的例题和相关知识点(二)

[SWPUCTF 2021 新生赛]Do_you_know_http 解题: 点击打开环境,是 提示说请使用wLLm浏览器访问 我们可以更改浏览器信息,在burp重放器中发包后发现是302重定向,但是提示说success成功,说明 我们修改是成功的&#xff…

20232803 2023-2024-2 《网络攻防实践》实践九报告

目录 1.实践内容2.实践过程2.1 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数2.2 利用foo函数的Bof漏洞,构造一个攻击输入字符串,覆盖返回地址,触发getShell函数2.3 注入一个自己制作的shellcode并运行…

GPU学习记一下线程分组相关

在compute的时候,是要dispatch一个数量的代表分了多少块任务集,dispatch的块内部也是有一个数量的,那么这些值怎么取的呢 内部,N卡32 外面dispatch的数量就是all/32 然后细说这个值 这有一个叫core的东西,就是相当于th…

【数据可视化-05】:Plotly数据可视化宝典

一、引言 数据可视化是机器学习流程中不可或缺的一部分。通过图形和图表展示数据,我们可以更直观地理解数据的分布、趋势和关联,从而更有效地进行数据分析、特征工程和模型评估。Plotly是一个功能强大且灵活的数据可视化库,它提供了丰富的图表…

Linux系统 -目录结构与配网

目录的特点 Windows中有C盘、D盘等,每个都是一个根系统是个多根系统 Linux中只有一个根是个单根系统 Linux-目录存储的内容 1、/root:管理员的家目录 2、/home:存储普通用户家目录的目录/3、/tmp:临时目录,这个目录存储…

合并K个升序链表

题目 解法一 优先级队列 思想 将每个链表中的一个节点存放到优先级队列中,本题采用小根堆,将小根堆中的根节点取出,插入到最终的链表中,并且将该节点在原链表中的下一个节点插入小根堆中(需要向下调整)&a…

Python查询和操作HTML文档库之pyquery使用详解

概要 在Web开发和数据抓取中,处理HTML文档是一项常见任务。Python的pyquery库提供了一个强大且灵活的方式来查询和操作HTML文档,类似于jQuery的语法。通过这篇文章,将深入了解pyquery的安装、特性、基本和高级功能,以及它在实际应用中的用例。 安装 安装pyquery相当简单,…

python:SunMoonTimeCalculator

# encoding: utf-8 # 版权所有 2024 ©涂聚文有限公司 # 许可信息查看: # 描述: https://github.com/Broham/suncalcPy # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # Datetime : 2024/5/14 21:59 # User …

MQTT_服务器的安装_1.3

此例子是以Windows系统安装开源版本的EMQX 下载 EMQX 下载并解压 解压如图 进入bin 文件夹在文件目录中输入cmd回车 启动服务器 然后在cmd中输入下面的代码(会弹出一个访问网络的选项,确认可以访问网络) emqx start 结果如图(…