如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。
所谓深浅拷贝,都是进行复制,那么区别主要在于复制出来的新对象和原来的对象是否会互相影响,改一个,另一个也会变
浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)
一、如何实现深拷贝
1 递归
function deepClone(source){ if(!source && typeof source !== 'object'){ throw new Error('error arguments', 'shallowClone'); } var targetObj = Array.isArray(source) ? [] : {}; for(var keys in source){ if(source.hasOwnProperty(keys)){ if(source[keys] && typeof source[keys] === 'object'){ targetObj[keys] = deepClone(source[keys]); //递归 }else{ targetObj[keys] = source[keys]; } } } return targetObj; } var A = [{name:"jack",age:20},{name:"marry",age:18},{name:"smilth",age:28}]; var c = deepClone(A); A[0].name = '李四'; console.log(c); console.log(A);
2 JSON.parse(JSON.stringify())
:
a.JSON.parse()
方法用来解析JSON字符串,构造由字符串描述的JavaScript值或对象。提供可选的 reviver 函数用以在返回之前对所得到的对象执行变换(操作)。
b.JSON.stringify()
方法将一个 JavaScript 对象或值转换为 JSON 字符串,如果指定了一个 replacer 函数,则可以选择性地替换值,或者指定的 replacer 是数组,则可选择性地仅包含数组指定的属性。
const obj1 = {person: {name:'李四',age: 20}}; const obj2 = JSON.parse(JSON.stringify(obj1)); obj2.person.name = '王五' console.log(obj1,obj2)
这样做是真正的Deep Copy,这种方法简单易用。
但是这种方法也有不少坏处,譬如它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。
这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象
,即那些能够被 json 直接表示的数据结构。RegExp对象是无法通过这种方式深拷贝。
也就是说,只有可以转成JSON
格式的对象才可以这样用,像function
没办法转成JSON。
3 jQuery 的 extend()
本人不会JQuery请看听风是风的博客
二、实现浅拷贝的方法
1 简单地复制语句
2 Object.assign方法:Object.assign
方法只会拷贝源对象自身的并且可枚举的属性到目标对象
需要注意的是:
Object.assign()可以处理一层的深度拷贝,如下:
var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = Object.assign({}, obj1); obj2.b = 100; console.log(obj1); // { a: 10, b: 20, c: 30 } <-- 沒被改到 console.log(obj2); // { a: 10, b: 100, c: 30 }
3 slice() : slice()
方法返回一个新的数组对象,这一对象是一个由 begin
和 end
决定的原数组的浅拷贝(包括 begin
,不包括end
)。原始数组不会被改变。
4 concat():concat
方法不会改变this
或任何作为参数提供的数组,而是返回一个浅拷贝,它包含与原始数组相结合的相同元素的副本
const array1 = ['a', 'b', ['c', 'f']]; const array2 = ['d', 'e']; const array3 = array1.concat(array2); array1[0] = 'A'; array1[2][0] = 'C' console.log(array1,array2,array3)
slice和concat方法一级属性不受影响,但是二级属性确没能拷贝成功。
第一层的属性确实深拷贝,拥有了独立的内存,但更深的属性却仍然公用了地址,所以才会造成上面的问题。
三、参考和引用