JavaScript 中堆和栈的区别

JS变量都存放在内存中,而内存给变量开辟了两块区域,分别为栈区域和堆区域
栈像个容器,容量小速度快
堆像个房间,容量较大


讲这些之前我们先说说基本数据类型引用数据类型

我们知道在js中的数据类型可以分为基本类型和引用类型。基本类型是存在栈内存中的,引用类型是存在堆内存中的,但是引用类型的引用还是存在栈内存中的。

let num1 = 1;
num1 = 2;
console.log(num1);  // 2

在这里插入图片描述

const p1 = {
    name: 'Tom',
    age: 20
}
const p2 = p1;
p2.name = 'oakley';
console.log(p1.name);  // "oakley"

在这里插入图片描述

基本类型 声明一个变量,多次赋值就会取取最后一个值
基本类型 可以直接复制,复制之后的内容和原内容没有什么联系,类似于开辟了一个新的空间
引用类型 直接赋值给另一个变量以后相互之间的修改会互相影响对方,进而引出浅拷贝与深拷贝的问题
基本类型 不能添加属性或者方法,而引用类型可以动态添加或删除属性/方法

学过数据结构的都知道 是一种 先进后出 的数据结构,栈内存是内存中用于存放临时变量的一片内存块。当声明一个基本变量时,它就会被存储到栈内存中。比如有这样一段代码,他们在栈内存中存储的形式如下表一样:

const a = 1;
const b = "1";
变量名变量值
b“1”
a1

而当其发生复制时,会把对应内存中的数据复制一份到新内存中,就像下面这样

const c = b
变量名变量值
c“1”
b“1”
a1

很显然,c,b两个变量占用了不同的存储空间,所以他们之间也并没有什么联系
栈内存的地址分配是连续的,所以在后续也不能对其进行进一步的扩充或者删除。

栈总结

栈内存的特点:存取速度快,但不灵活,同时由于结构简单,在变量使用完成后就可以将其释放,内存回收容易实现。

堆内存的存储不同与栈,虽然他们都是内存中的一片空间,但是堆内存存储变量时没有什么规律可言。

const p1 = {};
const p2 = {};
const p3 = {};

在这里插入图片描述

我们在访问引用类型时,需要在栈内存中查找 对应的地址,在去堆内存中取得真正的值,访问速度自然不及栈内存。

对引用类型进行复制

const p4 = p3;

在这里插入图片描述

可以看到,我们只是将地址复制了一遍,p4 和 p3 都是指向同一个地址,这就说明对 p4 进行修改时就会影响到 p3 的值。所以对引用类型进行复制时,应该把堆内存中的内容复制一遍,在将新地址赋值给新变量,这就涉及到深拷贝了, 那我就简单的实现下深拷贝:

深拷贝

// 第一种
const a = {};
const b = JSON.parse(JSON.stringfy(a));

// 第二种
function clone(obj, hash = new WeakMap()) {
  // 判断是否为 null 或者 typeof 返回类型是否为 object
  if (obj == null || typeof obj !== "object") return obj;
  else if (obj instanceof Date) return new Date(obj);
  else if (obj instanceof RegExp) return new RegExp(obj);
  
  // 判断集合是否有这个属性,有则直接 return obj
  if(hash.has(obj)) return hash.get(obj)
  const newObj = new obj.constructor();
    
  // 将属性和拷贝后的值作为一个map
  hash.set(obj, newObj);
    
  // 遍历 obj
  for (let key in Object.getOwnPropertyDescriptors(obj)) {
      // 过滤掉原型身上的属性
      if (obj.hasOwnProperty(key)) {
      	// 递归拷贝
        newObj[key] = clone(obj[key], hash);
      }
    
  }
  return newObj;
}

堆总结

堆内存的特点:使用灵活,可以动态增加或删除空间,但是存取比较慢

  • 22
    点赞
  • 142
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
JavaScript中,是用来存储变量和数据的两种不同的内存区域。 是一种后进先出(LIFO)的数据结构,用于存储基本类型的变量和引用类型的指针。当我们声明一个变量时,它的值会被直接存储在内存中。基本类型的值(如数字、布尔值、字符串等)被直接存储在中,而引用类型的变量则存储了指向内存中实际数据的指针。 是一种动态分配的内存区域,用于存储引用类型的数据。当我们创建一个引用类型的变量时,它的值实际上是一个指向内存中对象的引用。对象本身的数据存储在内存中,而中的变量只是存储了指向内存中对象的引用。 深拷贝是指创建一个新的对象,将原始对象的所有属性和嵌套对象的属性都复制到新对象中。这样,新对象和原始对象是完全独立的,对新对象的修改不会影响原始对象。在JavaScript中,可以使用不同的方法实现深拷贝,如使用JSON.parse(JSON.stringify(obj))或自定义递归函数来复制对象的属性和嵌套对象。 浅拷贝是指创建一个新的对象,将原始对象的属性复制到新对象中,但嵌套对象的引用仍然指向原始对象中的相同嵌套对象。这意味着对新对象的修改可能会影响原始对象。在JavaScript中,可以使用Object.assign()或展开运算符(...)来实现浅拷贝。 总结来说,用于存储基本类型的变量和引用类型的指针,而用于存储引用类型的数据。深拷贝是创建一个新对象并复制所有属性和嵌套对象的值,而浅拷贝只复制属性,嵌套对象的引用仍然指向原始对象。 #### 引用[.reference_title] - *1* *3* [JavaScript 中堆区别](https://blog.csdn.net/qq_29850249/article/details/110500006)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [JavaScript内存与内存分别是什么?](https://blog.csdn.net/qq_43807473/article/details/123816682)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值