一般来说,栈和堆的分配是指 C 或 C++ 编译的程序,写JS的根不关心这个层面上的问题。
由于JS脚本引擎是一种由 C 或 C++ 开发的“应用”,而且这种脚本“应用”并不再经过 C/C++ 编译器编译,所以这种“应用”内变量所处位置并不好说。
JavaScript 有两种数据类型
基本数据类型(存放在栈中): Number、String、Boolean、Null、Undefined。
引用数据类型(存在堆内存):Object、Array、Function、RegExp、Date。
浅复制与深复制只存在于引用数据类型当中。
堆和栈的区别
其实深拷贝和浅拷贝的主要区别就在于其内存中的存储类型不同。堆和栈都是内存中划分出来用来存储的区域。
栈(stack):是自动分配的内存空间,它由系统自动释放;栈内存是存储基本类型和指定代码的环境(执行上下文)。
堆(heap):是动态分配的内存,大小不定也不会自动释放;堆内存是用来存放引用类型的空间环境(object)
普通变量直接存在栈中执行上下文的变量环境或词法环境中,但是引用类型是把变量名存在栈中,该变量名的值是指向堆中的地址。
数据类型复制
基本数据类型的原始值是不可更改的:任何方法都无法更改一个原始值。比如字符串的所有方法看上去返回了一个修改后的字符串,实际上返回的是一个新的字符串值。
基本类型的比较是值的比较,只要它们的值相等就认为他们是相等的。
引用数据类型浅复制时,复制的是同一片的堆内存地址,修改数据时,是通过变量中储存的内存地址,找到堆内存中的引用数据类型修改,修改是同一组数据。
深复制时,复制的是不同的内存地址,修改数据时,是通过变量中储存的内存地址,根据内存地址找到堆内存中的引用数据类型修改,修改不是同一组数据
浅复制和深复制实现
直接用=赋值就是浅复制的实现方式。
深复制的话,数组的slice和concat方法,对象的 Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。使用 JSON.parse(JSON.stringify(object))
深复制函数:
深复制函数主要解决的问题是,如果某个属性是引用类型,需要把这个属性也给深复制一下。基本思路都是递归。
function deepCopy(obj) { var o; switch (typeof obj) { case 'undefined': break; case 'string': o = obj + ''; break; case 'number': o = obj - 0; break; case 'boolean': o = obj; break; case 'object': if (obj === null) { o = null; } else { if (obj instanceof Array) { o = []; for (var i = 0, len = obj.length; i < len; i++) { o.push(deepCopy(obj[i])); } } else { o = {}; for (var k in obj) { o[k] = deepCopy(obj[k]); } } } break; default: o = obj; break; } return o; }
function deepCopy(p,c){ c = c || {}; for (var i in p){ if(p.hasOwnProperty(i)){ if(typeof p[i] === 'object'){ c[i] = Array.isArray(p[i]) ? [] : {}; deepCopy(p[i],c[i]); }else{ c[i] = p[i]; } } } return c; }
参考:
https://www.cnblogs.com/mei123/p/8694943.html
https://www.zhihu.com/question/42231657
https://blog.csdn.net/SarcoMao/article/details/104640290
修改时间 2021-12-23