深复制和浅复制只针对像 Object, Array 这样的复杂对象。简单来说,浅复制只复制一层对象的属性,而深复制则递归复制了所有层级。
一、浅拷贝
let obj = {a: 1, b: [2,3]}
function shadowCopy (obj) {
var newObj = {};
for(let prop in obj) {
if(obj.hasOwnProperty(prop)) {
newObj[prop] = obj[prop];
}
}
return newObj;
}
let shadowObj = shadowCopy(obj);
因为浅复制只会将对象的各个属性进行依次复制,并不会进行递归复制。而 JavaScript 存储对象都是存地址的,所以浅复制会导致 obj.arr 和 shadowObj.arr 指向同一块内存地址。
二、深拷贝
- 深拷贝则是复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。它不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。这就不会存在上面 obj 和 shadowObj 的 arr 属性指向同一个对象的问题。
let simpleObj = {
a:1,
b:{
b1:1
},
c:[
{
c1:1
}
]
};
let simpleArr=[
{
a:[1,2,3]
},
{
b:1
},
{
p:[1,2]
}
]
let deepCopy = function (targetObj) {
let copiedObj = Array.isArray(targetObj) ? [] : {};
let ArrayDealer = function(arrayVal, copiedObj) {
arrayVal.forEach(function(arrVal, index) {
copiedObj[index] = {};
console.log(arrVal);
if(typeof arrVal == 'object') {
copy(arrval[index], copiedObj[index]);
}else{
copiedObj[index] = arrVal;
}
})
};
let ObjectDealer = function (targetObj, copiedObj) {
for(var key in targetObj) {
var val = targetObj[key];
copiedObj[key] = {};
//非引用类型节点
if(typeof val=='object'){
copy(val,copiedObj[key]);
}else{
copiedObj[key] = val;
}
}
}
let copy = function (targetObj, copiedObj) {
if(Array.isArray(targetObj)) {
ArrayDealer(targetObj, copiedObj);
}else{
ObjectDealer(targetObj, copiedObj);
}
}
copy(targetObj, copiedObj);
return copiedObj;
}
console.log(deepCopy(simpleObj));
console.log(deepCopy(simpleArr));
- 还有一种方法是借助JSON 全局对象,针对纯 JSON 数据对象的深复制,正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。
下面的例子是深拷贝对象和数组。
var cloneObj = function(obj){
var str, newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== 'object'){
return;
} else if(window.JSON){
str = JSON.stringify(obj), //系列化对象
newobj = JSON.parse(str); //还原
} else {
for(var i in obj){
newobj[i] = typeof obj[i] === 'object' ?
cloneObj(obj[i]) : obj[i];
}
}
- 也可以用jQuery的extend
var x = {
a: 1,
b: { f: { g: 1 } },
c: [ 1, 2, 3 ]
};
var y = $.extend({}, x), //shallow copy
z = $.extend(true, {}, x); //deep copy
y.b.f === x.b.f // true
z.b.f === x.b.f // false