0
点赞
收藏
分享

微信扫一扫

js数据类型与堆栈内存

在JavaScript中,它的内存分为三种类型:代码空间、栈空间、堆空间,其中代码空间用于存放可执行代码。

本文带大家来深入理解下栈空间与堆空间(堆内存与栈内存)

栈的认识

概念

栈也是一种数据呈线性排列的数据结构,

入栈

往栈中添加数据的操作就叫“入栈”,往栈中添加数据时,新数据被放在最上面。

js数据类型与堆栈内存_数据

出栈

从栈中取出数据的操作就叫“出栈”,从栈中取出数据时,会从最新的数据开始取。

js数据类型与堆栈内存_栈内存_02

优点

由于栈中存放数据的结构是后放进去的数据先取出来(后进先出),针对一些操作需要取最新数据时,选择栈作为数据结构是最合适的。

缺点

访问栈中的任意数据时,就需要从最新的数据开始取,效率较低。

栈内存空间

栈内存空间 就是用栈作为数据结构在内存中所申请的空间。

js数据类型与堆栈内存_数据_03

堆的认识

堆的特点

如图所示,每个节点由两个子节点,用线条连接即为堆。

  • 结点内的数字就是存储的数据
  • 堆中的每个结点最多有两个子节点
  • 树的形状取决于数据的个数
  • 节点的排列顺序为从上到下,同一行里则为从左到右
  • 堆的父节点必须小于子结点
堆的数据存储

在堆中存储数据时必须遵守这样一条规则:子结点必定大于父节点

  • 顶端的结点为根节点存储的数据为堆中的最小值
  • 新数据增加时会被放在堆的最底部靠左的位置
  • 堆的底部没有多余空间时,会另起一行把数据加在这一行的最左端
堆的数据获取

从堆中获取数据时,需要从最上面的数据开始取,取完数据后,堆需要进行重新排序,将最后的数据移到取出的结点位置。

堆内存空间

堆内存空间就是用堆作为数据结构在内存中所申请的空间。

通常情况下,堆数据结构指的是 二叉堆

二叉堆的特点:

  • 它是一颗完全二叉树
  • 二叉堆不是最小堆就是最大堆

我们画个图来描述下 最大堆最小堆 ,如下所示:

js数据类型与堆栈内存_bc_04

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

基本数据类型

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

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

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

例如:

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

定义了2个变量:

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

引用数据类型

除了之前提到的基本数据类型外,其他的都属于引用数据类型,例如:​​Array​​、​​Function​​、​​Object​​等。

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

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

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

例如:

let msgObj = {msg: "测试", id: 5};
let ages = [19, 22, 57]

对象和数组的指针存放在栈内存中,指针指向的数组存放在堆内存中

js数据类型与堆栈内存_bc_05

经典题目:

let a = {}, b = '0', c = 0;
a[b] = '珠峰';
a[c] = '培训';
console.log(a[b]);

js数据类型与堆栈内存_栈内存_06

注意:堆内存中,属性名是不可以重复的,且数字属性名0与字符串属性名’0’是一样的

let a={},b=Symbol('1'),c=Symbol('1');
a[b]='珠峰';
a[c]='培训';
console.log(a[b]);

对象的属性名不一定是字符串,又可能还是一个Symbol的值

变量复制

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

基本数据类型的复制

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

js数据类型与堆栈内存_数据_07

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

引用数据类型的复制

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

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

深拷贝与浅拷贝

浅拷贝

引用数据类型在复制时,改了其中一个数据的值,另一个数据的值也会跟着改变,这种拷贝方式我们称为浅拷贝

深拷贝

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

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

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



//abc = {name: "大白"}
//obj = {name: "大白", age: 20}

  • 手动去写循环遍历

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

举报

相关推荐

0 条评论