引
js中的深浅拷贝的区别主要是针对Object和Array这种复杂类型的数据而言的。简单来说,浅拷贝只复制最外层的数据,对于更深层级的数据复制的是地址,复制前后的数据指向相同的存储地址。而深拷贝复制了所有层级的数据。
一 浅拷贝
复制最外层的数据,对于更深层级的数据复制了地址,将对象oldObj拷贝给对象newObj后,修改newObj中的属性,oldObj中的内容也会跟着变化。
<script>
var oldObj = {
id: 1,
name: 'ammy',
contact: {
tel: 10086,
wechat: 'hello10086'
},
hobby: ['sing', 'dance', 'sports']
};
var newObj = {};
for(var k in oldObj) {
// k为属性名,oldObj[k]为属性值
newObj[k] = oldObj[k];
}
console.log(newObj);
</script>
从结果来看,是将对象型属性msg也拷贝了。但是,这样拷贝会存在一个问题,当修改newObj中的属性时,oldObj中的内容也会跟着改变。
newObj.contact.tel = '10000';
console.log(oldObj);
从拷贝结果可以看出,当修改newObj中的msg中的tel属性为10000时,oldObj中的属性也发生了改变。
这是因为JavaScript 存储对象都是存地址的,浅拷贝对于更层级的数据拷贝的是地址。将oldObj中msg的地址拷贝给newObj,newObj中msg的地址仍然指向仍然是原来obj中的地址,即拷贝前后的msg指向的是同一个地址,因此修改newObj中的数据会影响oldObj中的数据。
ES6中新增了浅拷贝的语法,Object.assign(newObj,oldObj),相比上述方法简洁许多。
二 深拷贝
深拷贝,递归拷贝每一层级的数据,将值赋值给对应的属性。修改拷贝后的newObj不会对oldObj产生影响。
function deepCopy(target, source) {
for (var k in source) {
// 获取属性值
var item = source[k];
// 判断,数据类型为复杂数据类型Array和Object时,进行递归复制,为简单数据类型时才能进行直接赋值拷贝。
if (item instanceof Array) {
target[k] = [];
deepCopy(target[k], item);
} else if (item instanceof Object) {
target[k] = {};
deepCopy(target[k], item);
} else {
target[k] = item;
}
}
}
deepCopy(newObj,oldObj);
console.log(newObj);
// 修改newObj属性
newObj.contact.tel = '10000';
console.log(oldObj);
注:由于Array也属于Object,因此判断时应先判断是否为Array类型再判断是否为Object类型。
从结果可以看出,深拷贝修改newObj的属性后oldObj中的内容并没有发生改变。在拷贝的过程中,通过判断数据类型对复杂数据进行递归复制,将值复制给对应的属性,从而成功复制每一层级的数据。
三 总结
浅拷贝只复制最外层的数据,对于更深层级的数据复制的是地址,复制前后的数据指向相同的存储地址。深拷贝复制所有层级的数据。