图片授权基于:CC0协议
要想理解浅拷贝和深拷贝需要先对「栈内存」和「堆内存」了解。
栈内存和堆内存是两种数据结构。
JavaScript 中的基础类型都保存在栈内存中,基础数据类型包括:String、Number、Boolean、Undefined、Null、Symbol(ES6)。
其他的就是引用类型。
引用类型的值保存在堆内存中,但在栈内存会有一个地址指针来指向堆内存的地址。
复制「基础类型」中的内容呢,就直接赋值了,复制「引用类型」中的内容复制是其「引用」,新老数据指向的都是一个引用(内容一样)。
https://www.jianshu.com/p/996671d4dcc4
var web = \\\'web\\\';
var webcopy = web;//复制web
console.log(webcopy);
webcopy = \\\'web1\\\';
console.log(webcopy);//web1
console.log(web);//web
「基础类型」webcopy 复制了 web,改变了 webcopy 值后,不影响 web 。
var web = [1,2,3];
var webcopy = web;
webcopy[0] = 0;
console.log(web);//[0,2,3]
console.log(webcopy);//[0,2,3]
「引用类型」web 是数组,复制 web 后,更改 webcopy 会改变 web 的值。
我理解的意思是:数组和对象内容都是存在堆空间里,webcopy 复制的时候复制 web 栈空间指针,它们指向的内容还是一样,所以,在改动 webcopy 的时候 web 也会被更改。
浅拷贝/浅复制
项目中获得了一个简单的对象或数组,如果只是复制值出来后并更改的话,之前的值也会被修改。
为了解决这个问题,我们可以用 slice 来实现一个「数组」的简单复制。
var web = [1,2,3];
var webcopy = web.slice();//数组「浅拷贝」
// var webcopy = web.concat(); //浅拷贝
// var webcopy = Array.from(web); //浅拷贝
webcopy[0] = 0;
console.log(web);//[1,2,3]
console.log(webcopy);//[0,2,3]
slice 不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。原数组的元素会按照下述规则拷贝:
如果该元素是个对象引用 (不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。
对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。
如果向两个数组任一中添加了新元素,则另一个不会受到影响。
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
slice 只能复制「基础类型」数据,如果数组里面包含「引用类型」,那 slice 复制的就是「引用」,更改新值会改变原来的值。
深拷贝/深复制
我常用的深拷贝的方法是:用 JSON.stringify() 将对象或者数组转换为一个 JSON字符串,再用 JSON.parse() 来解析JSON字符串。
JSON.parse(JSON.stringify(arr));
var web = {
\\\'one\\\':1,
\\\'two\\\':[
{
\\\'two1\\\':\\\'01\\\'
}
]
}
var webcopy = JSON.parse(JSON.stringify(web));//数组「深拷贝」
webcopy.two[0].two1 = \\\'00\\\';
console.log(web.two[0].two1);//01
console.log(webcopy.two[0].two1);//00
缺点是对于数组是中 Function 和 正则表达式 会被忽略。
我在掘金上看到一篇不错的文章:https://github.com/wengjq/Blog/issues/3 是关于「深复制」的,作者写的不错。还有下面的评论「用户coconilu」整理的也很好。
我找到一位国外朋友写的:
function deepCopy(o) {
var output, v, key;
output = Array.isArray(o) ? [] : {};
for (key in o) {
v = o[key];
output[key] = (typeof v === \\\'function\\\') ?
new Function(\\\"return \\\" + v.toString())() :
(typeof v === \\\"object\\\") ? copy(v) : v;
}
return output;
}
deepCopy 可以把 Function 复制出来。注:没有投入项目中使用。
参考资料:
[1]https://www.jianshu.com/p/996671d4dcc4
[2]https://juejin.im/entry/589c29a9b123db16a3c18adf
[3]https://www.codementor.io/avijitgupta/deep-copying-in-js-7x6q8vh5d
[4]https://www.cnblogs.com/penghuwan/p/7359026.html
[5]https://segmentfault.com/a/1190000006752076
原创文章,作者:小道研究,如若转载,请注明出处:https://www.sudun.com/ask/34501.html