js深拷贝和浅拷贝具体使用区别(js浅拷贝和深拷贝原理)

图片授权基于:CC0协议 

要想理解浅拷贝和深拷贝需要先对「栈内存」和「堆内存」了解。

栈内存和堆内存是两种数据结构。

JavaScript 中的基础类型都保存在栈内存中,基础数据类型包括:String、Number、Boolean、Undefined、Null、Symbol(ES6)。

其他的就是引用类型。

引用类型的值保存在堆内存中,但在栈内存会有一个地址指针来指向堆内存的地址。

复制「基础类型」中的内容呢,就直接赋值了,复制「引用类型」中的内容复制是其「引用」,新老数据指向的都是一个引用(内容一样)。

https://www.jianshu.com/p/996671d4dcc4

var web = \\\'web\\\';var webcopy = web;//复制webconsole.log(webcopy);webcopy = \\\'web1\\\';console.log(webcopy);//web1console.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);//01console.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

(0)
小道研究的头像小道研究
上一篇 2024年4月14日
下一篇 2024年4月14日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注