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

JavaScript 变量声明var、let、const

在 JavaScript 中,varletconst是用于声明变量的关键字。
letconst是JavaScript里相对较新的变量声明方式。
let用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
const声明一个只读的常量。一旦声明,常量的值就不能改变。
const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
对于const来说,只声明不赋值,就会报错。
示例:

const PI = 3.1415;
console.log(PI) // 3.1415PI = 3; // Uncaught TypeError: Assignment to constant variable.const a; // Uncaught SyntaxError: Missing initializer in const declaration

varletconst 的区别:

重复声明

  • var:可以重复声明同一个变量。
  • letconst:不允许在同一作用域内重复声明同一个变量。
var a = 1;
var a = 2;    // 不会报错let b = 3;
let b = 4;    // Uncaught SyntaxError: Identifier 'b' has already been declaredconst c = 5;
const c = 6;  // Uncaught SyntaxError: Identifier 'c' has already been declared

变量提升

  • var:存在变量提升,即在变量声明之前使用该变量,不会报错,只是值为 undefined
    当函数开始的时候,就会处理 var 声明(脚本启动对应全局变量)。
    换言之,var 声明的变量会在函数开头被定义,与它在代码中定义的位置无关(这里不考虑定义在嵌套函数中的情况)。
  • letconst:不存在变量提升,在声明之前使用会报错。

使用 var 声明,示例:

console.log(a);  // 输出 undefined
var a = 10;// 上面代码的实际执行顺序如下:
// var a;
// console.log(a);
// a = 10

使用var声明变量 a ,会发生变量提升,即脚本开始运行时,变量 a 已经存在了,但是没有值,所以会输出undefined

使用letconst声明,示例:

console.log(b);  // Uncaught ReferenceError: Cannot access 'b' before initialization
let b = 20;console.log(c) // Uncaught ReferenceError: Cannot access 'c' before initialization
const c = 30;message = "message";  // Uncaught ReferenceError: Cannot access 'message' before initialization
let message;

从程序执行进入代码块(或函数)的那一刻起,变量bc 就开始进入“未初始化”状态。它一直保持未初始化状态,直至程序执行到相应的 letconst语句。

ES6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
在代码块内,使用 letconst命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

作用域

  • var:函数作用域或全局作用域。在函数内使用 var 声明的变量,在函数外部无法访问;在函数外部使用 var 声明的变量则是全局变量。
  • letconst:块级作用域。即它们在 {} 内声明的变量,在 {} 外部无法访问。

注意:ES6 的块级作用域必须有大括号{},如果没有大括号,JavaScript 引擎就认为不存在块级作用域。

由于 var 会忽略代码块,因此我们有了一个全局变量 a

if (true) {var a = 10; // 使用 "var" 而不是 "let"
}
console.log( a ); // 10,变量在 if 结束后仍存在

对于循环,var 声明的变量没有块级作用域也没有循环局部作用域:

for (var i = 0; i < 10; i++) {var one = 1;
}
console.log(i);   // 10,"i" 在循环结束后仍可见,它是一个全局变量
console.log(one); // 1,"one" 在循环结束后仍可见,它是一个全局变量

在函数内部,var 声明的变量的作用域将为函数作用域:

function sayHi() {if (true) {var phrase = "Hello";}alert(phrase); // 能正常工作
}
sayHi();
console.log(phrase); // ReferenceError: phrase is not defined

使用 letconst, 该变量仅在if内部可见:

if (true) {let b = 20; // 使用 "let", 该变量仅在if内部可见const c = 30; 
}
console.log(b); // Uncaught ReferenceError: b is not defined
console.log(c); // Uncaught ReferenceError: c is not defined// 没有{},就没有块级作用域。词法声明不能出现在单语句上下文中
if(true) let a = 1;  // Uncaught SyntaxError: Lexical declaration cannot appear in a single-statement context// 必须要用{},才有块级作用域
if(true) { let a = 1; }

对于 ifforwhile 等,使用letconst{...} 中声明的变量也仅在内部可见:

for (let i = 0; i < 3; i++) {// 此时,想在这里输出循环条件的i,报错。// console.log(i); // Uncaught ReferenceError: Cannot access 'i' before initializationlet i = 'abc';console.log(i);  // abc
}

执行第一句console.log(i);报错是因为在循环体内部再次声明了i,并且在let声明之前使用了变量。
for循环还有一个特别之处:设置循环变量的那部分是一个父作用域,循环体内部是一个单独的子作用域。

值的可修改性

  • varlet:声明的变量的值可以修改。
  • const:声明的变量的值不能修改,但如果是对象或数组等引用类型,其属性可以修改。
var a = 10;
a = 20; // 可以修改let b = 30;
b = 40;  // 可以修改const c = 50;
c = 60;  // Uncaught TypeError: Assignment to constant variable.const arr = [1, 2, 3];
// 可以修改数组的元素
arr.push(4); 
console.log(arr);  // [1, 2, 3, 4]
// 将 arr 指向另一个数组,就会报错
arr = [4, 5, 6];  // Uncaught TypeError: Assignment to constant variable.const obj= {};// 为 obj 添加一个属性,可以成功
obj.prop = 123;
console.log(obj.prop); // 123// 将 obj 指向另一个对象,就会报错
obj = {}; // Uncaught TypeError: Assignment to constant variable.

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

如果真的想将对象冻结,应该使用Object.freeze方法。

const obj = Object.freeze({});// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
obj.prop = 123;

常量obj指向一个冻结的对象,所以添加新属性不起作用,严格模式时还会报错。

除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。

var constantize = (obj) => {Object.freeze(obj);Object.keys(obj).forEach( (key, i) => {if ( typeof obj[key] === 'object' ) {constantize( obj[key] );}});
};

相关文章:

JavaScript 变量声明var、let、const

在 JavaScript 中&#xff0c;var、let和const是用于声明变量的关键字。 let和const是JavaScript里相对较新的变量声明方式。 let用法类似于var&#xff0c;但是所声明的变量&#xff0c;只在let命令所在的代码块内有效。 const声明一个只读的常量。一旦声明&#xff0c;常量的…...

ipvlan: operation not supported 导致的POD不断重启

情况描述 接到反馈有一台虚拟机HA迁移了&#xff0c;需要检查一下上面业务是否正常&#xff0c;由于是K8S node节点&#xff0c;正常情况下重启会自动恢复的&#xff0c;不过抱着严谨的态度&#xff0c;上去看了一眼。 问题&#xff1a;发现docker运行正常&#xff0c;但是业…...

组蛋白乳酸化和RNA甲基化如何联动?请大数据把这个思路推给科研人

在细胞生物学中&#xff0c;基因表达调控是决定细胞功能与命运的核心过程之一。组蛋白作为修饰性蛋白&#xff0c;在调控基因转录中起着至关重要的作用。近年来&#xff0c;科学家们发现&#xff0c;组蛋白的多种化学修饰&#xff08;如甲基化、乙酰化、磷酸化等&#xff09;影…...

操作文件-Path

Java操作文件-Path Paths 参数说明 first&#xff1a;必选参数&#xff0c;表示路径的第一个组件。more&#xff1a;可选参数&#xff0c;表示路径的其他组件&#xff0c;可以传入多个。 创建路径对象 // 创建一个表示当前工作目录的Path对象 Path currentPath Paths.get…...

RAC(Teamcenter )开发,Bom行解包和打包的方法

1、打包 UnpackAllAction allAction new UnpackAllAction((AbstractBOMLineViewerApplication) currentApplication, "packAllAction"); new Thread(allAction).start();2、解包 UnpackCommand command new UnpackCommand(bomLine); command.executeModal();3、注…...

log4j2漏洞练习

log4j2 是Apache的一个java日志框架&#xff0c;我们借助它进行日志相关操作管理&#xff0c;然而在2021年末log4j2爆出了远程代码执行漏洞&#xff0c;属于严重等级的漏洞。apache log4j通过定义每一条日志信息的级别能够更加细致地控制日志生成地过程&#xff0c;受影响的版本…...

OpenEuler安装部署教程

目录 OpenEuler安装部署教程 MobaXterm一款全能的远程工具 yum安装软件 vim编辑器&#xff08;了解&#xff09; 防火墙 常用命令 网络工具netstat & telnet 进程管理工具top ps 磁盘free、fdisk 用户、组&#xff08;了解&#xff09; 权限&#xff08;了解&am…...

Canto - hackmyvm

简介 靶机名称&#xff1a;Canto 难度&#xff1a;简单 靶场地址&#xff1a;https://hackmyvm.eu/machines/machine.php?vmCanto 本地环境 虚拟机&#xff1a;vitual box 靶场IP&#xff08;Canto&#xff09;&#xff1a;192.168.130.53 windows_IP&#xff1a;192.1…...

【数据结构进阶】手撕红黑树

&#x1f525;个人主页&#xff1a; Forcible Bug Maker &#x1f525;专栏&#xff1a; C || 数据结构 目录 &#x1f308;前言&#x1f525;红黑树的概念&#x1f525;手撕红黑树红黑树结点的定义红黑树主体需要实现的成员函数红黑树的插入findEmpty和Size拷贝构造析构函数和…...

【C++从小白到大牛】类和对象

目录 一、面向过程和面向对象初步认识 二、类的引入 三、类的定义 类的成员函数两种定义方式&#xff1a; 1. 声明和定义全部放在类体中 2. 类声明放在.h文件中&#xff0c;成员函数定义放在.cpp文件中 成员变量命名规则的建议&#xff1a; 四、类的访问限定符 【访问限…...

Kafka 为什么这么快的七大秘诀,涨知识了

我们都知道 Kafka 是基于磁盘进行存储的&#xff0c;但 Kafka 官方又称其具有高性能、高吞吐、低延时的特点&#xff0c;其吞吐量动辄几十上百万。 在座的靓仔和靓女们是不是有点困惑了&#xff0c;一般认为在磁盘上读写数据是会降低性能的&#xff0c;因为寻址会比较消耗时间。…...

一文解决3D车道线检测:最新单目3D车道线检测综述

前言 场景理解是自动驾驶中极具挑战的任务&#xff0c;尤其是车道检测。车道是道路分割的关键&#xff0c;对车辆安全高效行驶至关重要。车道检测技术能自动识别道路标记&#xff0c;对自动驾驶车辆至关重要&#xff0c;缺乏这项技术可能导致交通问题和事故。车道检测面临多种…...

稳中向好,今年新招6000人

团子校招 近日&#xff0c;美团宣布开启面向 2025 届的校园招聘&#xff0c;招聘规模达 6000 人。 虽然相比京东&#xff08;宣布招聘 16000 人&#xff09;稍有逊色&#xff0c;但 6000 这个校招规模可一点不少。 要知道&#xff0c;京东是重自营的传统电商&#xff0c;16000 …...

使用kettle开源工具进行跨库数据同步

数据库同步可以用&#xff1a; 1、Navicat 2、Kettle 3、自己写代码 调用码神工具跨库数据同步 -连接 4、其它 实现 这里使用Kettle来同步&#xff0c;主要是开源的&#xff0c;通过配置就可以实现了 Kettle的图形化界面&#xff08;Spoon&#xff09;安装参考方法 ht…...

Golang | Leetcode Golang题解之第307题区域和检索-数组可修改

题目&#xff1a; 题解&#xff1a; type NumArray struct {nums, tree []int }func Constructor(nums []int) NumArray {tree : make([]int, len(nums)1)na : NumArray{nums, tree}for i, num : range nums {na.add(i1, num)}return na }func (na *NumArray) add(index, val …...

Golang | Leetcode Golang题解之第301题删除无效的括号

题目&#xff1a; 题解&#xff1a; func checkValid(str string, lmask, rmask int, left, right []int) bool {cnt : 0pos1, pos2 : 0, 0for i : range str {if pos1 < len(left) && i left[pos1] {if lmask>>pos1&1 0 {cnt}pos1} else if pos2 <…...

【Story】《程序员面试的“八股文”辩论:技术基础与实际能力的博弈》

目录 程序员面试中的“八股文”&#xff1a;助力还是阻力&#xff1f;1. “八股文”的背景与定义1.1 “八股文”的起源1.2 “八股文”的常见类型 2. “八股文”的作用分析2.1 理论基础的评价2.1.1 助力2.1.2 阻力 3. 实际工作能力的考察3.1 助力3.2 阻力 4. 面试中的背题能力4.…...

初步了解泛型

目录 泛型的引入 泛型 泛型 泛型类 泛型的上界 泛型的引入 之前学习的数组里面是存放着整型或者自字符串中一种的数组&#xff0c;如果想要在一个数组里面放多种类型数据&#xff0c;我们该怎么去做呢&#xff1f;Object类或许是一个好的解决方法&#xff0c;因为Object类…...

【C#】.net core 6.0 webapi 使用core版本的NPOI的Excel读取数据以及保存数据

欢迎来到《小5讲堂》 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景读取并保存NPOI信息NPOI 插件介绍基本功能示例代码写入 Excel 文件…...

C++推荐的oj网站

洛谷 信息学奥赛一本通 C语言网 codeforces 杭电oj...

为什么JSON.parse(JSON.stringify(obj))是糟糕的深拷贝?

为什么JSON.parse(JSON.stringify(obj))是糟糕的深拷贝&#xff1f;在JavaScript开发中&#xff0c;深拷贝是一个常见的需求。许多开发者会使用JSON.parse(JSON.stringify(obj))来实现深拷贝&#xff0c;因为它简单快捷。这种方法实际上存在许多问题&#xff0c;并不是一个可靠…...

即插即用系列(代码实践) | CVPR 2025:SCSegamba:轻量级结构感知 Mamba,重新定义裂缝分割 SOTA

论文题目:SCSegamba: Lightweight Structure-Aware Vision Mamba for Crack Segmentation in Structures 中文题目:SCSegamba:用于结构裂缝分割的轻量级结构感知视觉Mamba 论文出处:arXiv 2025 (天津理工大学等) 论文原文 (Paper):https://arxiv.org/pdf/2503.01113 代码 …...

AWPortrait-Z实测体验:无需修图技能,一键生成高质量人像照片

AWPortrait-Z实测体验&#xff1a;无需修图技能&#xff0c;一键生成高质量人像照片 1. 初识AWPortrait-Z&#xff1a;普通人也能用的专业级人像美化工具 1.1 什么是AWPortrait-Z AWPortrait-Z是基于Z-Image构建的人像美化LoRA模型&#xff0c;经过科哥团队的二次开发&#…...

电脑软件n-Track Studio Suite 9(多音轨录音软件

链接&#xff1a;https://pan.quark.cn/s/d201bf13487fn-Track Studio Suite是一款非常专业的电脑多音轨录音软件&#xff0c;它不仅支持高质量的录音、编码、音频编辑还支持刻录音频或创建文件。n-Track Studio Suite拥有非常简洁大方的界面&#xff0c;为用户提供了非常全面的…...

HyperAgent:基于LLM的智能浏览器自动化工具实战指南

1. 项目概述与核心价值如果你和我一样&#xff0c;曾经为了写一个网页自动化脚本&#xff0c;在Playwright或Puppeteer那冗长的选择器&#xff08;Selector&#xff09;和复杂的等待逻辑里挣扎过&#xff0c;那么HyperAgent的出现&#xff0c;绝对会让你眼前一亮。简单来说&…...

DeepSeek V4论文降AI干货,2026年4月10个实用技巧

DeepSeek V4 在 2026-04-24 正式上线&#xff0c;写论文的速度比 V3 又快了一截&#xff0c;但随之而来的麻烦也很现实&#xff1a;AI 检测率比上一代更高。我自己在 04-24 当晚拿一篇用 V4 生成的开题报告去测&#xff0c;知网 AIGC 疑似 67.4%&#xff0c;维普 58%&#xff0…...

VSCode 2026远程容器连接卡顿?92%开发者忽略的4个Dockerd配置陷阱与实时修复命令清单

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;VSCode 2026远程容器连接卡顿现象全景诊断 VSCode 2026 版本在启用 Remote-Containers 扩展连接 Docker 容器时&#xff0c;高频出现 UI 响应延迟、终端输入滞后、文件同步中断等复合型卡顿现象。该问题…...

ARM硬件断点与BREAKWRITE命令详解

1. ARM硬件断点与BREAKWRITE命令概述在ARM架构的嵌入式系统开发中&#xff0c;硬件断点(Hardware Breakpoint)是调试复杂实时系统的关键工具。与软件断点不同&#xff0c;硬件断点不修改目标代码&#xff0c;而是利用处理器内置的调试硬件来监控特定内存访问行为。BREAKWRITE作…...

3个颠覆性体验:APKMirror客户端如何重新定义你的应用下载方式

3个颠覆性体验&#xff1a;APKMirror客户端如何重新定义你的应用下载方式 【免费下载链接】APKMirror 项目地址: https://gitcode.com/gh_mirrors/ap/APKMirror 想象一下这样的场景&#xff1a;你需要下载某个应用的历史版本&#xff0c;但在搜索引擎中翻找了半小时&am…...

4点法、7点法、8点法、5点法——OpenCV多视图几何四大矩阵求解器源码深度拆解

两张不同角度拍摄的照片,怎么算出来场景的三维结构? 这个问题困扰了计算机视觉研究者三十多年。答案藏在三个矩阵里:单应性矩阵 H、基础矩阵 F、本质矩阵 E。OpenCV 为每一个矩阵都实现了专门的求解算法,它们分别需要 4 个、7 个(或 8 个)、5 个点对应。这些数字不是凭空…...