引用类型、内存原理与对象

一、内存两大区域:栈内存 Stack、堆内存 Heap

计算机给 JS 划分两块地方存放数据,分工完全不一样。

  1. 栈内存(Stack)

空间小,读写速度快

存放两类东西:

基本类型的真实值

引用类型的内存地址(编号),不是对象本身!

栈的变量生命周期简单:函数执行完毕、变量失效,直接出栈销毁。

  1. 堆内存(Heap)

空间很大,读写速度比栈慢

只存引用类型真正的数据:对象、数组,一大坨键值对。

最最重要一句话:

引用类型的对象本体永远待在堆;栈里面的变量,只拿着堆的地址编号,相当于门牌号。

举个例子代码:

js

运行

let user = { name: "小明", age: 18 }

内存发生的事情:

JS 在堆内存开辟一块空间,存入完整对象 { name:"小明", age:18 },假设这块堆的地址编号:0xaa01

在栈内存创建变量 user,变量 user 里面不存对象,只存地址 0xaa01

当写 user.name:JS 读取栈中 user 的地址 0xaa01,拿着地址去堆里面找到真实对象,读取 name 属性。

形象比喻:

堆 = 一套真实房子;栈变量 = 写着房子门牌号的小纸条。

user 手里只有纸条(地址),房子本体在堆。访问属性就是拿着纸条去找房子。

二、基本类型 vs 引用类型赋值本质区别

  1. 基本类型:赋值 = 复制一份真实的值(完全拷贝)

js

运行

let a = 100

let b = a

b = 200

console.log(a) // 100

内存过程:

栈:a = 100

let b = a:把 100 这个值复制一份给 b,栈里出现两份独立数据

修改 b=200,只改动 b 自己的数据,a 不受任何影响。

两个完全独立副本,井水不犯河水。

  1. 引用类型:赋值 = 复制地址纸条!不会复制堆里面的对象!

js

运行

let u1 = { name: "小明" }

let u2 = u1

u2.name = "小红"

console.log(u1.name) // 小红

// ② 给变量直接赋全新对象:给u2换一张新门牌号,断开和u1的联系

u2 = { name: "小李" }

①:改房子里面家具 → 所有人看见变化

②:直接换一套新房子,旧房子不受影响。

三、浅拷贝、深拷贝:如何真正产生新对象

需求:不想共用同一个堆对象,想要两个独立对象。

浅拷贝:只复制对象第一层,生成新堆对象;嵌套对象依旧共用地址

js

运行

let obj1 = { a: 10, info: { age: 18 } }

// 浅拷贝写法1:展开运算符

let obj2 = { ...obj1 }

// 浅拷贝写法2 Object.assign

// let obj2 = Object.assign({}, obj1)

内存行为:

堆开辟新对象给 obj2,复制第一层 a:10;

但是里面的 info 是对象,只复制 info 的地址,info 对象还是原来堆里那一个。

js

运行

obj2.a = 999

console.log(obj1.a) //10 第一层互不干扰

obj2.info.age = 999

console.log(obj1.info.age) //999 嵌套对象还是共享堆

浅拷贝只能解决一层,嵌套引用依旧存在。

深拷贝:所有层级全部新建堆对象,彻底切断引用

简单快速方案(局限性:不能拷贝函数、undefined、symbol)

js

运行

let obj2 = JSON.parse(JSON.stringify(obj1))

相关推荐
啾咪orJIUMI33 分钟前
Vue 3 + 高德地图封装实战:点位、区域、Loca 流光与 Vue 信息窗体
前端·vue.js
掘金者阿豪35 分钟前
AI数据库不只是向量检索:从数据语义到库内智能计算的技术演进
前端
梦里寻码38 分钟前
我用 NestJS + Vue3 写了一套完整的研发管理系统(58 表 / 229 API / 130 项断言,全开源
前端·后端·算法
FRing0340 分钟前
vue2干货总结8(路由模块封装、router-link、声明式导航、路由重定向、编程式导航)
开发语言·前端·vue.js·vue2
旖旎夜光42 分钟前
【C++ 基础入门】C++ 多态(上):虚函数、重写、override/final 与抽象类
开发语言·c++·笔记·学习
SameX1 小时前
HarmonyOS ArkUI Dialog 复用 用 @CustomDialog + enum type 做多类型统一管理的做法
前端
starzy19901 小时前
深入理解Scala嵌套函数:作用域封装之道
开发语言·scala
AiMan1 小时前
豆包爱学还是不可以导出左侧所有对话,只能单容导出,方法不对吗
前端
Sakura_j_h_1 小时前
从零写一个 MCP stdio Server:用 Python 校验博客文章格式
开发语言·python·自动化·ai工具·mcp·json-rpc
AiMan1 小时前
Grok生成的内容能否下载吗?
前端