深入理解js数据类型与堆栈内存(下)

简介: 深入理解js数据类型与堆栈内存(下)

变量类型与堆栈内存的关系


基本数据类型


我们知道JS的基本数据类型有7种:


  • string
  • number
  • boolean
  • null
  • undefined
  • symbol
  • bigInt


基本数据类型变量保存在栈内存中,因为基本数据类型占用空间小、大小固定,通过值来访问,属于被频繁使用的数据。


接下来,我们通过一个例子来讲解下,基本数据类型在栈内存中的存储:


let name = "大白";
let age = 20;


上述代码中,我们定义了2个变量:


  • name为string类型
  • age为number类型


我们画个图来描述下它在栈内存的存储:


640.png


                                  image-20210323152445985


注意⚠️:闭包中的基本数据类型变量是保存在堆内存里的,当函数执行完弹出调用栈后,返回一个内部函数的一个引用,这时候函数的变量就会转移到堆上,因此内部函数依然能访问到上一层函数的变量。


引用数据类型


除了上个章节提到的基本数据类型外,其他的都属于引用数据类型,例如:ArrayFunctionObject等。


引用数据类型存储在堆内存中,引用数据类型占据空间大、大小不固定,如果存储在栈中,将影响程序的运行性能。


引用数据类型会在栈中存储一个指针,这个指针指向堆内存空间中该实体的起始地址。


当解释器寻找引用值时,会先检索其在栈中的地址,取得地址后,从堆中获得实体。


我们举个例子来描述下上述话语:


// 基本数据类型-栈内存
let name = "大白";
// 基本数据类型-栈内存
let age = 20;
// 基本数据类型-栈内存
let info = null;
// 对象指针存放在栈内存中,指针指向的对象放在堆内存中
let msgObj = {msg: "测试", id: 5};
// 数组的指针存放在栈内存中,指针指向的数组存放在堆内存中
let ages = [19, 22, 57]


上述代码中:


  • 我们创建了两个变量msgObjages,他们的值都是引用类型(object、array)
  • 堆内存空间采用二叉堆作为数据结构,msgObjages的具体值会存在堆内存空间中
  • 存储完成后,堆内存空间会返回这两个值的引用地址(指针)
  • 拿到引用地址后,这个引用地址会和它的变量名对应起来,存放在栈内存空间中
  • 在查找变量msgObjages的具体值时,会先从栈内存空间中获取它的引用地址
  • 获取到引用地址后,通过引用地址在堆内存空间的二叉堆中查找到对应的值。


我们画个图来描述下上述话语,如下所示:


堆内存空间中的Object,表示的是存储在空间中的其他对象的引用值。


640.png

                                 image-20210323170843691


我们来理解下堆内存空间与堆内存的区别:

堆内存空间:相当于一个采用二叉堆作为数据结构的容器。

堆内存:指的是一个引用类型的具体值。

堆内存存在于堆内存空间中。


变量复制


接下来,我们从内存角度来看下变量复制。


基本数据类型的复制


我们通过一个例子来看下基本类型的复制,代码如下所示:


let name = "神奇的程序员";
let alias = name;
alias = "大白";


上述代码中:


  • namealias都是基本类型,它们的值存储在栈内存。
  • 它们分别有各自独立的栈空间
  • 因此,修改alias的值,name不受影响


我们画个图来描述下:


640.png

                                 image-20210323203531067


引用数据类型的复制


接下来,我们通过一个例子来看下引用类型的复制,代码如下所示:


let book = {title:"书", id: 12}
let info = book;
info.title = "故事书";
console.log(book.title); // 故事书


上述代码中:


  • infobook都是引用类型,它们的引用存在栈内存,值存在堆内存
  • 它们的值指向同一块堆内存,栈内存中会复制一份相同的引用


我们画个图来描述下:


640.png

                             image-20210323213720148


深拷贝与浅拷贝


通过上述章节的学习,我们了解到引用数据类型在复制时,改了其中一个数据的值,另一个数据的值也会跟着改变,这种拷贝方式我们称为浅拷贝


在实际开发中,我们希望引用类型复制到新的变量后,二者是独立的,不会因为一个的改变而影响到另一个。这种拷贝方式就称为深拷贝


深拷贝,实际上就是重新在堆内存中开辟一块新的空间,把原对象的数据拷贝到这个新地址空间里来,通常来说,我们有两种方法:


  • 转一遍JSON再转回来 ,但是这个办法有一个问题,这只能转化一般常见数据,function,undefined等类型都无法通过这种变回来
  • 手动去写循环遍历


我们来看下第一种方法,代码如下所示:


const data = { name: "大白" };
const obj = JSON.parse(JSON.stringify(data));
obj.age = 20;
console.log("data = ", data);
console.log("obj = ", obj);


运行结果如下:


640.png

                              image-20210323233500632


最后,我们来看下第二种写法,代码如下所示:


const data = [{ name: "大白" }];
let obj = data.map(item => item);
obj.push({ name: "神奇的程序员" });
console.log("data = ", data);
console.log("obj = ", obj);


运行结果如下:


640.png

                            image-20210323234043404


代码地址


本文为《JS原理学习》系列的第4篇文章,本系列的完整路线请移步:JS原理学习 (1) 》学习路线规划


本系列文章的所有示例代码,请移步:js-learning


写在最后


至此,文章就分享完毕了。


我是神奇的程序员,一位前端开发工程师。


如果你对我感兴趣,请移步我的个人网站,进一步了解。


  • 公众号无法外链,如果文中有链接,可点击下方阅读原文查看😊
相关文章
|
13天前
|
JavaScript 前端开发
js变量的作用域、作用域链、数据类型和转换应用案例
【4月更文挑战第27天】JavaScript 中变量有全局和局部作用域,全局变量在所有地方可访问,局部变量只限其定义的代码块。作用域链允许变量在当前块未定义时向上搜索父级作用域。语言支持多种数据类型,如字符串、数字、布尔值,可通过 `typeof` 检查类型。转换数据类型用 `parseInt` 或 `parseFloat`,将字符串转为数值。
18 1
|
18天前
|
存储 Java 测试技术
滚雪球学Java(18):解密JavaSE中的堆栈:你真的了解Java内存吗?
【4月更文挑战第7天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
42 1
滚雪球学Java(18):解密JavaSE中的堆栈:你真的了解Java内存吗?
|
10天前
|
存储 JavaScript 前端开发
【JavaScript技术专栏】JavaScript基础入门:变量、数据类型与运算符
【4月更文挑战第30天】本文介绍了JavaScript的基础知识,包括变量(var、let、const)、数据类型(Number、String、Boolean、Undefined、Null及Object、Array)和运算符(算术、赋值、比较、逻辑)。通过实例展示了如何声明变量、操作数据类型以及使用运算符执行数学和逻辑运算。了解这些基础知识对初学者至关重要,是进阶学习JavaScript的关键。
|
11天前
|
存储 JavaScript 前端开发
JavaScript引用数据类型
JavaScript引用数据类型
|
11天前
|
JavaScript 前端开发
JavaScript 基本数据类型
JavaScript 基本数据类型
|
11天前
|
存储 缓存 JavaScript
【Web 前端】JS哪些操作会造成内存泄露?
【4月更文挑战第22天】【Web 前端】JS哪些操作会造成内存泄露?
|
11天前
|
JavaScript 前端开发
【Web 前端】JS中检测数据类型的有哪些?
【4月更文挑战第22天】【Web 前端】JS中检测数据类型的有哪些?
|
11天前
|
存储 前端开发 JavaScript
【Web 前端】JS数据类型有哪些?区别?
【4月更文挑战第22天】【Web 前端】JS数据类型有哪些?区别?
|
20天前
|
存储 JavaScript 前端开发
JavaScript的数据类型主要分为两大类:基本数据类型和引用数据类型
【4月更文挑战第20天】JavaScript的数据类型主要分为两大类:基本数据类型和引用数据类型
21 6
|
14天前
|
存储
浮点数在内存中的存储
浮点数在内存中的存储
24 0