拷貝分為深拷貝和淺拷貝,通俗來講就是B復制了A的內容,當A進行了修改以后,看B是否變化,如果變化了就是淺拷貝,如果沒有變化就是深拷貝。
淺拷貝:
var a = {
key1:"111"
}
function copy(p){
// console.log(p)
var c = {};
for(var i in p){
c[i] = p[i];
// console.log(i) // key1
}
return c;
}
// copy(a);
a.key2 = ["you","me"];
var b = copy(a);
b.key3 = "ours";
console.log(a.key3); // undefined
console.log(b.key3) // ours
// console.log(b) // {key1:"111",key2:["you","me"]}
b.key2.push("us")
console.log(b.key2); // ["you", "me", "us"]
console.log(a.key2); // ["you", "me", "us"]

深拷貝:
第一種:遞歸深拷貝
function deepClone(obj){
// 定義一個變量 並判斷是數組還是對象
var objClone = Array.isArray(obj) ? [] : {};
if(obj && typeof obj === "object" && obj != null){
// 判斷obj存在並且是對象類型的時候 因為null也是object類型,所以要單獨做判斷
for(var key in obj){ // 循環對象類型的obj
if(obj.hasOwnProperty(key)){ // 判斷obj中是否存在key屬性
if(obj[key] && typeof obj[key] === "object"){ // 判斷如果obj[key]存在並且obj[key]是對象類型的時候應該深拷貝,即在堆內存中開辟新的內存
objClone[key] = deepClone(obj[key]);
}else{ // 否則就是淺復制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
var a = {
name:"key1",
eat:[
"蘋果",
"香蕉"
]
}
b = deepClone(a);
// console.log(b);
a.eat = [
"蘋果",
"香蕉",
"橙子"
];
console.log(a); // {name:"key1",eat:["蘋果","香蕉","橙子"]}
console.log(b) // {name:"key1",eat:["蘋果","香蕉"]}
遞歸運行效率低,次數過多的話容易造成棧溢出。
第二種:JSON的parse和stringify方法實現深復制
function deepClone(obj){
// console.log(obj);
// console.log(typeof obj);
var _obj = JSON.stringify(obj); // 對象轉成字符串
// console.log(_obj);
// console.log(typeof _obj);
var objClone = JSON.parse(_obj); // 字符串轉成對象
// console.log(objClone);
// console.log(typeof objClone);
return objClone;
}
var a = [0,1,[2,3],4];
b = deepClone(a)
a[0] = 6;
a[2][0] = 7;
console.log(a); // [6,1,[7,3],4]
console.log(b); // [0,1,[2,3],4]
第三種:jq的$.extend 深拷貝
var a = [0,1,[2,3],4];
b = $.extend(true,[],a);
a[0] = 1;
a[2][0] = 7;
console.log(a); // [1,1,[7,3],4];
console.log(b); // [0,1,[2,3],4];
$.extend參數:
第一個參數是布爾值,是否深復制
第二個參數是目標對象,其他對象的成員屬性將被附加到該對象上
第三個及以后的參數是被合並的對象
解決深拷貝中因為循環引用造成的死循環問題(使用數組方法):
function find(arr,item){
for(var i=0; i<arr.length; i++){
if(arr[i].source === item){
return arr[i]
}
}
return null;
}
function isObject(obj) {
return typeof obj === 'object' && obj != null;
}
function deepClone(source,uniqueList){
if(!isObject(source)) return source;
if(!uniqueList) uniqueList = []; // 初始化數據
var target = Array.isArray(source) ? [] : {};
var uniqueData = find(uniqueList,source);
if(uniqueData) return uniqueData.target;
uniqueList.push({
source:source,
target:target
});
for(var key in source){
if(Object.prototype.hasOwnProperty.call(source,key)){
if(isObject(source[key])){
target[key] = deepClone(source[key], uniqueList) // 傳入數組
}else{
target[key] = source[key];
}
}
}
return target;
}
var a = {
name:"key1",
eat:[
"蘋果",
"香蕉"
]
}
b = deepClone(a);
// console.log(b);
a.eat[2] = "桃";
a.d = a;
console.log(a);
console.log(b);
