资讯专栏INFORMATION COLUMN

深入理解JS深浅拷贝

JackJiang / 1783人阅读

摘要:深拷贝相比于浅拷贝速度较慢并且花销较大。所以在赋值完成后,在栈内存就有两个指针指向堆内存同一个数据。结果如下扩展运算符只能对一层进行深拷贝如果拷贝的层数超过了一层的话,那么就会进行浅拷贝那么我们可以看到和展开原算符对于深浅拷贝的结果是一样。

JS中数据类型

基本数据类型: undefined、null、Boolean、Number、String和Symbol(ES6)

引用数据类型: Object(Array, Date, RegExp, Function)

深浅拷贝

深浅拷贝只是针对引用类型的,因为引用类型是存放在堆内存中,在栈地址有一个或者多个地址来指向推内存的某一数据

浅拷贝:

被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。

浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象,如果你修改了“副本”的值,那么原来的对象也会被修改

深拷贝:

深拷贝是一个整个独立的对象拷贝,深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。

深拷贝把要复制的对象所引用的对象都复制了一遍。如果你修改了“副本”的值,那么原来的对象不会被修改,两者是相互独立的。

用例子看深浅拷贝 赋值实现浅拷贝
let arr = [22, 44, 66, 88];
let co = arr;
co[0] = 11;
console.log(arr, co);

结果如图:

我们本来想把 arr 赋值给 co ,当我们修改co数组中第一个元素时,却发现了原始数组arr发生了改变
很显然,这就是一个浅拷贝的例子

原理:
对于引用类型,赋值操作符只是把存放在栈内容中的指针赋值给另外一个变量。
所以在赋值完成后,在栈内存就有两个指针指向堆内存同一个数据。
也就可以说两个变量在共用着同一个数据,这就是浅拷贝。
JSON实现深拷贝
let arr = [22, 44, 66, 88];
let jso = JSON.parse(JSON.stringify(arr));
jso[0] = 11;
console.log(arr, jso);

结果如图:

对比之前赋值的结果,我们发现原来的数组arr并没有被改变,可以说两者是相互独立的
很显然,这就是一个深拷贝的例子

原理:
JSON.parse() 方法用于将一个 JSON 字符串转换为对象。
JSON.stringify() 方法用于将 JavaScript 值(通常为对象或数组)转换为 JSON 字符串。
在JSON.stringify()完成后,对象就转为了字符串,也就可以说实实在在的复制了一个值,不存在引用之说。
再利用JSON.parse()转为对象,这样达到深拷贝的目的

JSON实现深拷贝的缺陷:
来看下面例子:

let obj = {
    nul: null,
    und: undefined,
    sym: Symbol("sym"),
    str: "str",
    bol: true,
    num: 45,
    arr: [1, 4],
    reg: /[0-9]/,
    dat: new Date(),
    fun: function() {},  
}
console.log(JSON.parse(JSON.stringify(obj)))

结果如图:

我们可以发现有些属性被忽略了:

undefined

symbol

function

可以看得出来JSON实现深拷贝也有不足之处

ES6新特性实现拷贝 Object.assign()

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
Object.assign(target, ...sources)
target目标对象。 sources源对象。 返回的是目标对象

let obj = {
    a: {
        a1: "a1"
    },
    b: "b"
}
let ass = Object.assign({}, obj);
ass.a.a1 = "aaa";
aconsole.log(obj, ass);

我们看下结果:

我们可以看到a1的值被改变,而b的值没有被改变,说明了:

Obejct.assign()只能对一层进行深拷贝 
如果拷贝的层数超过了一层的话,那么就会进行浅拷贝
展开运算符(...)

对象的扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

let obj = {
    a: {
        a1: "a1"
    },
    b: "b"
}
let ass = {...obj};
ass.a.a1 = "aaa";
ass.b = "bbb"

结果如下:

扩展运算符只能对一层进行深拷贝 
如果拷贝的层数超过了一层的话,那么就会进行浅拷贝

那么我们可以看到Object.assign()和展开原算符对于深浅拷贝的结果是一样。
如果拷贝的层数超过了一层的话,那么就会进行浅拷贝
所以要慎用这两个来进行拷贝!!!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100714.html

相关文章

  • 深入理解 Javascript 之 JS深浅拷贝

    摘要:动手实现深拷贝利递归来实现对对象或数组的深拷贝。递归思路对属性中所有引用类型的值进行遍历,直到是基本类型值为止。深拷贝只对对象自有属性进行拷贝测试数据拷贝方式其实也是一种继承的方式,当然继承还是有其他方法的感谢支持 深浅拷贝 基本类型 & 引用类型 ECMAScript中的数据类型可分为两种: 基本类型:undefined,null,Boolean,String,Number,Symb...

    Tikitoo 评论0 收藏0
  • js深浅复制

    摘要:总结综上所述,数组的深拷贝比较简单,方法没有什么争议,对象的深拷贝,比较好的方法是用的方法实现,或者递归实现,比较简单的深复制可以使用实现参考资料知乎中的深拷贝和浅拷贝深入剖析的深复制 深浅复制对比 因为JavaScript存储对象都是存地址的,所以浅复制会导致 obj 和obj1 指向同一块内存地址。我的理解是,这有点类似数据双向绑定,改变了其中一方的内容,都是在原来的内存基础上做...

    Apollo 评论0 收藏0
  • 一篇文章彻底搞懂JS深浅拷贝和const

    摘要:图数据类型图引用类型深浅拷贝问题不知道什么是深拷贝和浅拷贝的请先去并在调试台自己操作一下,这篇文章只会说明为何中会有这种问题。所以有的时候我们为了避免浅拷贝,会用一些方式实现深拷贝。 首先要了解的js基础 基本数据类型:Object、undefined、null、Boolean、Number、String、Symbol (ES6新加) Object包括: Array 、Date 、R...

    MyFaith 评论0 收藏0
  • 复习Javascript专题(四):js中的深浅拷贝

    摘要:基本数据类型的复制很简单,就是赋值操作,所以深浅拷贝也是针对,这类引用类型数据。它会抛弃对象的。另外,查资料过程中还看到这么一个词结构化克隆算法还有这一篇资料也有参考,也写得比较详细了的深浅拷贝 基本数据类型的复制很简单,就是赋值操作,所以深浅拷贝也是针对Object,Array这类引用类型数据。 浅拷贝对于字符串来说,是值的复制,而对于对象来说则是对对象地址的复制;而深拷贝的话,它不...

    MobService 评论0 收藏0

发表评论

0条评论

JackJiang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<