当你想修改某个数据但又不影响原来的数据时就需要对原数据进行拷贝。
JS
来说,基本数据的赋值是基于值的没啥影响,但是对象的赋值是基于地址的,这就有影响,具体可以看下JS
的数据存储。
浅复制
浅复制,只复制第一层,更新深层的还是基于地址的赋值,如数组[].concat(origin); origin.slice();
对象Object.assgin({}, origin)
这个简单,不多说。
深拷贝
先来说个最简单的,如果数据很简单,就是单纯的对象数据,可以使用JSON.parse(JSON.stringify())
但是这个对简单的就可以,对复杂的对象是有问题的。
- 当对象通过 JSON.stringify()转换成字符时有些属性值的字据类型会被忽略:
Function, Symbol, undefined
,
- 数组通过 JSON.stringify()转换成字符时有些属性值的字据类型会被转成null
Function, Symbol, undefined
- JSON.stringify()转换过程中,正则对象侧是转成一个空对象、内部有循环引用时,会报错。
复杂的对象深拷贝要考虑的有两个问题:循环引用
和 对象层次深
这两个问题,用递归的话都会有超出内在问题。
首先,循环引用
可以用一个数组把遇到的对象(需要遍历的)都保存起来,对于后面的对象复现可以判断是否已遍历过,遍历过的直接赋值就可以,这样就不会因为循环引用而无限循环赋值了。
对象层次很深时,对于递归,会出现爆栈。深层次的递归可以用尾调优来解决,但是这个深拷贝貌似不好用这个方法,可以用循环来拷贝,直接上代码,用注释来解释。
1 | // 查找 是否已保存过的,用来解决循环引用问题 |
如果用了第三方库的,如underscore,lodash,jQuery
等都有深复制的函数,不需要自己写,自己写只是为了了解对象的复制可能存在哪些问题,还有应对可能的面试。