JavaScript深拷贝与浅拷贝的区别
注:深浅拷贝的区别只适用于array【数组】与object【对象】
一、数组Array
1、拷贝情况
浅拷贝:相当于使两个数组指针指向相同的地址,任一个数组元素发生改变,影响另一个。
深拷贝:两数组指针指向不同的地址,数组元素发生改变时不会相互影响。
2、实现
1、浅拷贝:赋值运算符
var a = [1, 2, 3]
b = a
console.log("a: ",a)
console.log("b: ",b)
b[0] = 99;
console.log("---- after changed array b ----- ")
console.log("a: ",a)
console.log("b: ",b)
运行结果:a数组元素随b数组改变
2、深拷贝:
方法一:JavaScript的slice函数
var a = [1, 2, 3]
b = a.slice(0)
console.log("a: ",a)
console.log("b: ",b)
b[0] = 99;
console.log("---- after changed deepClone array b ----- ")
console.log("a: ",a)
console.log("b: ",b)
运行结果:a数组元素未随b数组改变
方法二、JavaScript的concat函数
var a = [1, 2, 3]
b = a.concat([])
console.log("a: ",a)
console.log("b: ",b)
b[0] = 99;
console.log("---- after changed deepClone array b ----- ")
console.log("a: ",a)
console.log("b: ",b)
运行结果:a数组元素未随b数组改变
方法三、jquery的extend函数
1、一维数组
var a = [1, 2, 3]
// jQuery.extend([deep], target, object1, object2, object3...),
// [deep]:默认false【不能显式设置为false;值为true时深度合并对象。
// target:其他对象复制到该对象
// object:被合并的对象
b = $.extend(true, [], a)
console.log("a: ",a)
console.log("b: ",b)
b[0] = 99;
console.log("---- after changed deepClone array b ----- ")
console.log("a: ",a)
console.log("b: ",b)
运行结果:此例中【deep】值为true和false时结果相同
2、二维数组
1、【deep】值为false,对象不进行深度合并
var a = [[1, 2, 3], 4, [5, 6]]
b = $.extend([], a)
console.log("a: ",a)
console.log("b: ",b)
b[0][0] = 99;
console.log("---- after changed deepClone array b ----- ")
console.log("a: ",a)
console.log("b: ",b)
运行结果:修改前的数组也受到影响,暂不清楚原因
2、【deep】值为true,对象进行深度合并
var a = [[1, 2, 3], 4, [5, 6] ]
b = $.extend(true, [], a)
console.log("a: ",a)
console.log("b: ",b)
b[0][0] = 99;
console.log("---- after changed deepClone array b ----- ")
console.log("a: ",a)
console.log("b: ",b)
运行结果:
二、对象Object
1、拷贝情况
- 浅拷贝:只拷贝对象的第一层属性,对于属性中包含的属性不会复制;由于JavaScript对象均以地址的方式存贮,所以浅复制导致多个对象的属性均指向同一块地址。
- 深拷贝:对对象的每一层属性进行递归复制,深层次的属性也不会指向同一块地址【同一个对象】。
2、实现
1、浅拷贝:
方法一、自定义函数
function shallowCopy(obj1, obj2) {
for( var key in obj1){
if (obj1.hasOwnProperty(key)) {
obj2[key] = obj1[key]
}
}
}
function showKeys(obj) {
for( var key in obj){
if (obj.hasOwnProperty(key)) {
console.log(key, ":", obj[key]);
}
}
}
var a = {
sing:true,
dance:{today:false, tommorrw:true}
}
b = {}
shallowCopy(a, b)
showKeys(a)
showKeys(b)
b.sing = false
b.dance.today = true
console.log("------------- after changed object b -------------- ")
showKeys(a)
showKeys(b)
运行结果:由于对象的浅拷贝只复制第一层属性,因此obj b第一层属性的改变不会影响复制源,而第二层属性仍指向同一块地址,因此obj b的dance属性的today属性作改变之后,同一块地址处的obj a的dance属性的today属性同时变化了。
方法二、jquery的extend函数:【deep】参数为false
function showKeys(obj) {
for( var key in obj){
if (obj.hasOwnProperty(key)) {
console.log(key, ":", obj[key]);
}
}
}
var a = {
sing:true,
dance:{today:false, tommorrw:true}
}
b = $.extend({}, a)
showKeys(a)
showKeys(b)
b.sing = false
b.dance.today = true
console.log("------------- after changed object b -------------- ")
showKeys(a)
showKeys(b)
运行结果:同上
2、深拷贝
方法:jquery的extend函数:【deep】参数为true
function showKeys(obj) {
for( var key in obj){
if (obj.hasOwnProperty(key)) {
console.log(key, ":", obj[key]);
}
}
}
var a = {
sing:true,
dance:{today:false, tommorrw:true}
}
b = $.extend(true, {}, a)
showKeys(a)
showKeys(b)
b.sing = false
b.dance.today = true
console.log("------------- after changed object b -------------- ")
showKeys(a)
showKeys(b)
运行结果:多层属性深拷贝,互不影响
三、实现js基本数据类型的拷贝
实现对object、array、number、boolean、string的值进行复制,其中object和array需要判断,用各自的方法进行复制,其他数据类型可直接复制。
function cloneAll(obj) {
if (obj instanceof Array) {
var result = []
for (var i = 0, max = obj.length; i < max; i++) {
result[i] = cloneAll(obj[i])
}
return result
}
else if(obj instanceof Object){
var result = {}
for(key in obj){
result[key] = cloneAll(obj[key])
}
return result
}
else{
return obj
}
}