浅拷贝
什么是浅拷贝
先看一个例子,想要将 obj
对象中的属性都复制一份给一个新的对象,使两个对象拥有相同的各自的属性而不会互相干扰,使用 for in
方法循环遍历进行赋值操作。
代码如下:
var obj = {
id:'1',
name:'obj',
info:{
desc:'我是obj对象'
}
}
var copyObj ={}
for(let key in obj){
copyObj[key]=obj[key]
}
copyObj.info.desc='我是copyObj对象'
console.log(obj)//copyObj.info.desc='我是copyObj对象'
console.log(copyObj)//copyObj.info.desc='我是copyObj对象'
拷贝之后打印输出这两个对象,看似没有毛病,但是当 copyObj.info.desc
属性值修改后原来的 obj
对象对应的该属性值也被修改了,因为 info
属性是一个对象,其值是该子对象在内存中的地址值,即 info
属性是对该对象的引用,所以所以obj
和 copyObj
的info
属性都是引用的同一个内存中的对象,一个修改导致另一个数据也改变。
总结: 浅拷贝就是只复制对象最外层的属性,而对引用类型的数据拷贝的只是对其的引用。
实现浅拷贝的方法
可以实现浅拷贝的方法有:
1、 for in
(循环遍历进行赋值,上面例子就是这种方法实现的)
2、Object.assign(target,sources) ES6 新增方法实现浅拷贝
使用 ES6 新增方法 Object.assign
方法进行浅拷贝
Object.assign(target, …sources)
方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。并返回目标对象。
Object.assign
方法只会拷贝源对象自身的并且可枚举的属性到目标对象。拷贝的是属性值,如果源对象的属性值是一个对象的引用,那么目标对象该属性也只指向那个引用所以也是浅拷贝
var obj = {
id:'1',
name:'obj',
info:{
desc:'我是obj对象'
}
}
const assignObj= Object.assign({}, obj);
obj.info.desc='我是复制的assignObj'
console.log(obj);
3、使用展开语法,扩展运算符,(比较其与Object.assign方法的区别,Object.assign会调用setter 是什么意思?????)
使用展开语法,Rest/Spread Properties for ECMAScript 提议(stage 4) 对 字面量对象 增加了展开特性。其行为是, 将已有对象的所有可枚举(enumerable)属性拷贝到新构造的对象中.
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
var clonedObj = { ...obj1 };
// 克隆后的对象: { foo: "bar", x: 42 }
var mergedObj = { ...obj1, ...obj2 };
// 合并后的对象: { foo: "baz", x: 42, y: 13 }
注意:
Object.assign() 函数会触发 setters,而展开语法则不会。
4、Array.prototype.concat
Array.prototype.concat 也可以实现数组的浅拷贝,concat方法不会改变 this
或任何作为参数提供的数组,而是返回一个浅拷贝,它包含与原始数组相结合的相同元素的副本。
语法:var new_array = old_array.concat(value1,value2,…)
,该方法用于合并两个或多个数组,如果省略了valueN参数,则concat会返回一个它所调用的已存在的数组的浅拷贝
var arr=['1','2',{id:'1',name:'obj'}]
var concatArr=arr.concat()
console.log('concatObj:',concatArr)
深拷贝
深拷贝: 每一级别的数据都会拷贝,深拷贝是对对象以及对象的所有子对象进行拷贝。
实现方法:
1、使用for in 循环+递归实现深拷贝
var originalObj = {
id:'1',
name:'obj',
info:{
desc:'我是originalObj对象'
},
arr:['length','width','height']
}
var targetObj={}
function deepCopy(target,scource) {
for(let key in scource){
if(scource[key] instanceof Array){
target[key]=[]
deepCopy(target[key],scource[key])
}else if(scource[key] instanceof Object){
target[key]={}
deepCopy(target[key],scource[key])
}else{
//原始值类型的数据
target[key]=scource[key]
}
}
}
deepCopy(targetObj,originalObj)
targetObj.info.desc='我是深拷贝的targetObj'
console.log(originalObj);
console.log(targetObj);
深拷贝输出结果:
2、使用 JSON.sringify 和 JSON.parse
使用 JSON.stringify 方法将对象转换为字符串,在通过JSON.parse(text,) 将字符串重新转换成对象。
var originalObj = {
id:'1',
name:'obj',
info:{
desc:'我是originalObj对象'
},
arr:['length','width','height']
}
let cp=JSON.stringify(originalObj)
cp=JSON.parse(cp)
cp.info.desc='我是JSON.stringify深拷贝的cp'
console.log(cp)