拷贝分为深拷贝和浅拷贝,通俗来讲就是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);