JavaScript 中堆和栈的区别以及深度拷贝的方法

本文解析了JavaScript中变量存储的栈与堆特性,讲解了基本类型和引用类型的区别,涉及复制行为、浅拷贝与深拷贝,以及栈与堆内存的特点和操作。

前言: 

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

先说说基本数据类型引用数据类型

我们知道在js中的数据类型可以分为基本类型和引用类型。

基本类型是存在栈内存中的,引用类型是存在堆内存中的,但是引用类型的引用还是存在栈内存中的。 

常见的基本数据类型:Number、String 、Boolean、Null和Undefined

常见的引用数据类型:Object 、Array 、Function 、Data等。

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;
}

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值