深復制和淺復制只針對像 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