【前端】JavaScript 变量引用、内存与数组赋值:深入解析三种情景

文章目录
- 💯前言
- 💯场景一:直接赋值与重新引用
- 为什么结果不是 `[3, 4, 5]`?
- 1. 引用与赋值的基本概念
- 2. 图示分析
- 关键总结
- 💯场景二:引用指向的变化
- 为什么结果还是 `[1, 2, 3]`?
- 对象引用与原始数据的区别
- 重新赋值与直接修改的差异
- 💯场景三:修改数组内容
- 为什么结果变成了 `[1, 2, 6]`?
- JavaScript 中的内存共享
- 💯深入理解 JavaScript 的内存模型与赋值行为
- 1. JavaScript 中的值类型和引用类型
- 2. 内存分配与垃圾回收
- 💯如何避免引用带来的问题
- 1. 浅拷贝与深拷贝
- 2. 使用 `Object.assign` 或 `lodash.cloneDeep`
- 💯小结

💯前言
- JavaScript 是一种基于对象的脚本语言,常用于前端开发。初学者在使用 JavaScript 时,通常会遇到一些关于变量引用和赋值的困惑。本文将详细讨论三种不同的代码场景,结合 JavaScript 的变量引用与内存模型,深入分析为什么这些代码输出会如此不同。希望通过对这些原理的探讨,能够帮助您更好地理解 JavaScript 中的变量引用机制。
💯场景一:直接赋值与重新引用
首先,我们来看以下的代码片段:
var arr = [1, 2, 3];
var newArr = arr;
newArr = [3, 4, 5];
console.log(arr); // 输出是什么?
运行结果:
[1, 2, 3]

为什么结果不是 [3, 4, 5]?
![]()
要理解这个问题,我们需要深入理解 JavaScript 中的变量赋值与引用的区别。
1. 引用与赋值的基本概念
![]()
在 JavaScript 中,基本数据类型(如 number、string 等)是按值传递的,而复杂数据类型(如数组、对象)是按引用传递的。
在代码中,var arr = [1, 2, 3] 创建了一个数组 [1, 2, 3],并且将其引用赋值给变量 arr。此时,arr 保存的是数组在内存中的引用(地址),而不是数组的值本身。
然后,执行 var newArr = arr;,这意味着 newArr 保存了与 arr 相同的引用。也就是说,newArr 和 arr 都指向了相同的内存地址,这个内存中存储的是数组 [1, 2, 3]。
当我们执行 newArr = [3, 4, 5]; 时,newArr 被重新赋值,指向了一个新的数组 [3, 4, 5] 的内存地址。此时,newArr 不再指向原来的数组 [1, 2, 3],而是指向了一个全新的数组。而 arr 依然保持指向原始数组的引用,因此打印 arr 时结果仍然是 [1, 2, 3]。
2. 图示分析
![]()
-
初始状态:
arr和newArr都指向[1, 2, 3]。
-
重新赋值后:
newArr指向新的数组[3, 4, 5]。arr依然指向原数组[1, 2, 3]。

关键总结
![]()
在 JavaScript 中,给一个变量赋予一个新的数组时,并不会改变原来的数组,而是创建了一个新的引用。如果希望改变所有引用同一数组的变量,那么需要对数组本身进行修改,而不是重新赋值。
💯场景二:引用指向的变化
接下来看第二个代码片段:
var arr = [1, 2, 3];
var newArr = arr;
arr = [4, 5, 6];
console.log(newArr); // 输出是什么?
运行结果:
[1, 2, 3]

为什么结果还是 [1, 2, 3]?
![]()
在这个场景中,我们遇到了类似的问题。在执行 var newArr = arr; 之后,newArr 和 arr 都指向同一个数组 [1, 2, 3]。但是,当执行 arr = [4, 5, 6]; 时,arr 被重新赋值,指向了一个新的数组 [4, 5, 6]。
需要注意的是,这种赋值不会影响到 newArr,因为 newArr 依旧保持指向原来的数组 [1, 2, 3]。简单来说,arr 重新指向了一个新的对象,而 newArr 还在指向原来的数组。
对象引用与原始数据的区别
![]()
在 JavaScript 中,对象、数组等复杂数据类型的变量并不直接保存数据的值,而是保存引用。当我们对变量重新赋值时,我们只是改变了它指向的内存地址,而原来的引用仍然有效。这也是为什么在打印 newArr 时,它依旧指向 [1, 2, 3]。
重新赋值与直接修改的差异
![]()
如果我们希望改变 newArr 也能看到新数组的变化,就不能直接给 arr 重新赋值,而是需要修改数组本身的内容,比如:
arr.push(4);
这样,arr 和 newArr 都会看到新的内容。
💯场景三:修改数组内容
最后,我们来看第三个代码片段:
var arr = [1, 2, 3];
var newArr = arr;
arr[2] = 6;
console.log(newArr); // 输出是什么?
运行结果:
[1, 2, 6]

为什么结果变成了 [1, 2, 6]?
![]()
在这里,我们需要理解的一个重要概念是“修改数组的内容”和“重新赋值”的区别。
var arr = [1, 2, 3];创建了一个数组,并将其引用赋值给arr。var newArr = arr;将arr的引用赋值给newArr,此时arr和newArr都指向同一个数组。arr[2] = 6;直接修改了数组的第三个元素。
由于 arr 和 newArr 都指向相同的数组,这意味着对数组内容的任何更改对这两个变量都是可见的。因此,当 arr[2] 被修改为 6 时,newArr 看到的也是修改后的数组 [1, 2, 6]。
JavaScript 中的内存共享
![]()
在 JavaScript 中,数组和对象是通过引用来传递的。当多个变量引用同一个数组时,修改这个数组的内容将影响到所有引用该数组的变量。这种行为称为内存共享。
要理解内存共享,可以将数组或对象看作是存在于某个位置的数据块,而变量是指向这个数据块的“指针”。当我们通过一个变量修改数据块时,所有引用这个数据块的变量都会反映出相应的变化。

💯深入理解 JavaScript 的内存模型与赋值行为
![]()
为了更好地理解上述三种情况,我们还需要进一步了解 JavaScript 的内存管理和变量赋值行为。
1. JavaScript 中的值类型和引用类型
![]()
JavaScript 中的数据类型分为两类:
- 基本数据类型(值类型):包括
Number、String、Boolean、Null、Undefined、Symbol、BigInt。这些类型的数据是按值传递的,这意味着每个变量都存储数据的副本。 - 引用数据类型:包括
Object、Array、Function等。这些类型的数据是按引用传递的,变量保存的是对象的内存地址,而不是对象本身。
对于基本数据类型,变量赋值是直接复制值的副本,因此两个变量之间不会互相影响。对于引用类型,变量保存的是对象在内存中的地址,两个引用指向相同的地址意味着它们共享相同的内存内容。
2. 内存分配与垃圾回收
![]()
JavaScript 的内存分为两种主要区域:
- 栈内存(Stack Memory):用于存储基本类型的值和引用类型的引用。
- 堆内存(Heap Memory):用于存储引用类型的实际内容(对象、数组等)。
当执行赋值操作 var newArr = arr 时,newArr 和 arr 都指向堆内存中的同一个数组对象,因此对数组内容的修改对这两个变量来说是可见的。而当重新赋值 arr = [4, 5, 6] 时,arr 被重新赋予了一个新的引用,因此它和 newArr 分道扬镳。
💯如何避免引用带来的问题
![]()
在实际开发中,共享引用数据类型可能会带来一些不可预见的副作用,因此有时我们希望克隆数组或对象,以避免修改对其他变量产生影响。
1. 浅拷贝与深拷贝
![]()
浅拷贝 只复制对象的第一层引用,而 深拷贝 会递归复制所有嵌套的对象和数组。
-
浅拷贝的方法:使用
Object.assign()或展开运算符...。var arr = [1, 2, 3]; var shallowCopy = [...arr]; // 浅拷贝 shallowCopy[0] = 9; console.log(arr); // [1, 2, 3] console.log(shallowCopy); // [9, 2, 3] -
深拷贝的方法:使用
JSON.parse(JSON.stringify(obj))(这种方式有局限性,无法拷贝函数和某些特殊对象)。var obj = { a: 1, b: { c: 2 } }; var deepCopy = JSON.parse(JSON.stringify(obj)); deepCopy.b.c = 9; console.log(obj.b.c); // 2 console.log(deepCopy.b.c); // 9
2. 使用 Object.assign 或 lodash.cloneDeep
![]()
Object.assign() 可以用来实现对象的浅拷贝,而 lodash 库提供了一个更强大的深拷贝方法 _.cloneDeep(),可以递归地复制嵌套的对象和数组。
💯小结

在 JavaScript 中,理解变量赋值、引用以及内存模型对于掌握语言的行为至关重要。在本文中,我们详细探讨了三种代码场景,并通过对比分析深入理解了以下几点:
- 变量赋值与引用:赋值为引用数据类型时,变量保存的是内存地址,而不是数据本身。因此,重新赋值并不会影响其他引用该数据的变量。
- 内存模型:JavaScript 中,栈内存用于存储基本类型和引用地址,而堆内存用于存储复杂对象的内容。对引用对象的操作会影响到所有指向该内存地址的变量。
- 修改数组内容与重新赋值:直接修改数组的内容会影响所有引用该数组的变量,而重新赋值则会让变量指向一个新的对象,不影响其他引用。

相关文章:
【前端】JavaScript 变量引用、内存与数组赋值:深入解析三种情景
博客主页: [小ᶻZ࿆] 本文专栏: 前端 文章目录 💯前言💯场景一:直接赋值与重新引用为什么结果不是 [3, 4, 5]?1. 引用与赋值的基本概念2. 图示分析 关键总结 💯场景二:引用指向的变化为什么…...
本地项目运行提示跨域问题
项目背景:我使用phpwebstudy在本地搭建了一个项目,然后前端是http://localhost:8080/ 后端我直接创建了一个本地域名,例如www.abc.com 然后vue.config.js配置如下,这个配置在我所有线上环境是没有任何问题的 devServer: {proxy…...
C++ —— string类(上)
目录 string的介绍 string类功能的使用介绍 constructor —— 构造 介绍使用(1)(2)(4) :构造、拷贝构造、带参构造 介绍(3):拷贝string类对象的一部分字符…...
React Native Mac 环境搭建
下载 Mac 版Android Studio 下载 安装 JDK 环境 Flutter 项目实战-环境变量配置一 安装 Node.js 方式一 通过Node.js 官网下载 下载完成后点击安装包进行安装 安装完成...
Python Web 开发的路径管理艺术:FastAPI 项目中的最佳实践与问题解析20241119
Python Web 开发的路径管理艺术:FastAPI 项目中的最佳实践与问题解析 引言:从路径错误到模块化管理的技术旅程 在现代 Python Web 开发中,路径管理是一个常常被忽视却非常重要的问题。尤其是在使用像 FastAPI 和 Tortoise ORM 这样的框架时…...
Rust derive macro(Rust #[derive])Rust派生宏
参考文章:附录 D:派生特征 trait 文章目录 Rust 中的派生宏 #[derive]基础使用示例:派生 Debug 派生其他常用特征示例:派生 Clone 和 Copy 派生宏的限制和自定义派生自定义派生宏上面代码运行时报错了,以下是解释 结论…...
springboot嗨玩旅游网站
摘 要 嗨玩旅游网站是一个专为旅行爱好者打造的在线平台。我们提供丰富多样的旅游目的地信息,包括景点信息、旅游线路、商品信息、社区信息、活动推广等,帮助用户轻松规划行程。嗨玩旅游网站致力于为用户提供便捷、实用的旅行服务,让每一次旅…...
杰发科技AC7840——EEP中RAM的配置
sample和手册中示例代码的sram区地址定义不一样 这个在RAM中使用没有限制,根据这个表格留下足够空间即可 比如需要4096字节的eep空间,可以把RAM的地址改成E000,即E000-EFFF,共4096bytes即可。...
从零开始的c++之旅——map_set的使用
1.序列式容器和关联式容器 序列式容器:逻辑结构为线性序列的数据结构,两个位置之间没有紧密的关系,比如两者交换一下还是序列式的容器,例如string,vector,deque,array等。 关联式容器࿱…...
Docker中的一些常用命令
find / -type f -name “文件名” 2>/dev/null 寻找所有目录中的这个文件 pwd 查看当前目录的地址 docker pull 镜像名 强制拉镜像 docker run 运行docker systemctl daemon-reload 关闭docker systemctl start docker 启动docker systemctl restart docker 重启docker /…...
自存 sql常见语句和实际应用
关于连表 查询两个表 SELECT * FROM study_article JOIN study_article_review 查询的就是两个表相乘,结果为两个表的笛卡尔积 相这样 这种并不是我们想要的结果 通常会添加一些查询条件 SELECT * FROM study_articleJOIN study_article_review ON study_art…...
python | argparse模块在命令行的使用中的重要作用
import argparseclass TestCases:def __init__(self, nameNone, expect_resultNone):self.name nameself.expect expect_resultself.parser argparse.ArgumentParser() # 创建命令解析器self.add_arguments() # 方法 : 添加命令self.args, _ self.parser.par…...
【HCIP]——OSPF综合实验
题目 实验需求 根据上图可得,实验需求为: 1.R5作为ISP:其上只能配置IP地址;R4作为企业边界路由器,出口公网地址需要通过PPP协议获取,并进行CHAP认证。(PS:因PPP协议尚未学习&#…...
PW系列工控电脑复制机:效率与精度双重提升
工控电脑复制应用:效率与精度的双重提升 随着现代企业对大数据、数据备份、和跨平台兼容性需求的快速增长,工控电脑已成为数据密集型产业的核心设备。针对工控环境中大量数据复制的特殊需求,PW系列NVMe/SATA PCIe SSD复制机(如PW…...
学习QT第二天
QT6示例运行 运行一个Widgets程序运行一个QT Quick示例 工作太忙了,难得抽空学点东西。-_-||| 博客中有错误的地方,请各位道友及时指正,感谢! 运行一个Widgets程序 在QT Creator的欢迎界面中,点击左侧的示例…...
11.20作业
题目一: 题目: // 数组的行列转置 代码: // 数组的行列转置 #include <stdio.h> int main() {int a[2][3], i, j, b[3][2];printf("输入一个两行三列的数组a:\n");for (i 0; i < 2; i)for (j 0; j < 3; j){scanf…...
Ubuntu Linux使用前准备动作_使用root登录图形化界面
Ubuntu默认是不允许使用 root 登录图形化界面的。这是出于安全考虑的设置。但如果有需要,可以通过以下步骤来实现使用 root 登录: 1、设置 root 密码 打开终端,使用当前的管理员账户登录系统。在终端中输入命令sudo passwd root,…...
DICOM核心概念:显式 VR(Explicit VR)与隐式 VR(Implicit VR)在DICOM中的定义与区别
在DICOM(Digital Imaging and Communications in Medicine)标准中,VR(Value Representation) 表示数据元素的值的类型和格式。理解显式 VR(Explicit VR)与隐式 VR(Implicit VR&#…...
源码分析Spring Boot (v3.3.0)
. ____ _ __ _ _/\\ / ____ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | _ | _| | _ \/ _ | \ \ \ \\\/ ___)| |_)| | | | | || (_| | ) ) ) ) |____| .__|_| |_|_| |_\__, | / / / /|_||___//_/_/_/:: Spring Boot :: (v3.3.0)//笔记背…...
IPv6 NDP 记录
NDP(Neighbor Discovery Protocol,邻居发现协议) 是 IPv6 的一个关键协议,它组合了 IPv4 中的 ARP、ICMP 路由器发现和 ICMP 重定向等协议,并对它们作出了改进。该协议使用 ICMPv6 协议实现,作为 IPv6 的基…...
PDF-Extract-Kit-1.0精彩案例:IEEE论文PDF中LaTeX公式无损提取演示
PDF-Extract-Kit-1.0精彩案例:IEEE论文PDF中LaTeX公式无损提取演示 1. 引言:当学术研究遇上PDF公式提取难题 如果你经常需要阅读或处理学术论文,尤其是IEEE这类技术文档,一定遇到过这样的烦恼:看到一篇论文里的公式非…...
想做市场品牌策划?这3大秘诀让你的品牌脱颖而出!
行业痛点分析当前品牌策划领域面临诸多技术挑战。许多企业有产品无品牌,产品品质过硬、技术领先,但缺乏清晰的品牌定位与价值表达,陷入 “酒香也怕巷子深” 的困境,只能靠低价竞争。数据表明,约 60%的企业因品牌定位不…...
如何用OHHTTPStubs彻底改变iOS网络测试:从入门到精通的完整指南
如何用OHHTTPStubs彻底改变iOS网络测试:从入门到精通的完整指南 【免费下载链接】OHHTTPStubs AliSoftware/OHHTTPStubs: OHHTTPStubs是一个iOS和macOS的Objective-C和Swift库,用于在单元测试或者开发阶段模拟网络请求。它允许开发者设置HTTP stubs&…...
Flet跨平台GUI开发:从入门到实战
1. 为什么选择Flet开发跨平台GUI? 最近几年,Python在GUI开发领域一直缺少一个真正意义上的跨平台解决方案。传统的Tkinter功能有限,PyQt虽然强大但商业授权复杂,Kivy的语法又不够直观。直到我发现了Flet这个宝藏框架,它…...
Neovim文本编辑器
链接:https://pan.quark.cn/s/ce457be69098Neovim是一款基于Vi编辑器的文本编辑器,Neovim是Vim的一个分支,旨在解决Vim的一些缺点并提供额外特性。Neovim具有更好的性能和稳定性,支持异步插件和脚本,改进了对现代用户界…...
EXE Ver 适用于 未安装Python 以及包的Windows OS
上图~EXE Ver END...
深入解析CAN报文中的Motorola字节排序:MSB与LSB的实战对比
1. 从汽车仪表盘说起:为什么需要了解CAN字节排序 去年调试一辆新能源车的仪表盘时,我遇到了一个诡异现象:车速显示在80km/h时突然跳变成20km/h。排查三天后发现,问题出在CAN报文解析时搞混了Motorola的MSB和LSB排序方式。这个经历…...
Labview下的ADC参数测试上位机软件:动态与静态参数计算及波形显示
ADC参数测试上位机,通过将ADC的数字量输入上位机,上位机可以计算出动态参数 ENOB SFDR SNR 总谐波失真 以及静态参数 DNL和INL等参数。 其中动态参数的计算以及时序和频域的波形显示均采用matlab模块计算。 使用labview编写隔壁工位的张工最近快被ADC测…...
基于QT(C++)+Oracle实现的(界面)教务管理系统
一、选题背景 教务管理系统是基本每个高校都有的一个系统,教务系统管理系统充分利用互联网络B/S管理系统模式,以网络为平台,为各个学校教务系统的管理提供一个平台,帮助学校管理教务,用一个账号解决学校教务教学管理&…...
2025届毕业生推荐的降重复率平台实际效果
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 针对维普检测系统具备能识别 AI 生成内容的特性情形之下,若要降低文本里的 AI 痕…...
