浅拷贝: 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。(使用栈中的地址,而非堆中的数据)
深拷贝:深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。(使用堆中的数据,而非栈中的地址)
深拷贝的方法:
1. JSON方法
var obj1 = {
name: 'shen'
}
var obj2 = JSON.parse(JSON.stringify(obj1))
obj2.name = 'shenzhiyong'
console.log('obj1:', obj1) // obj1: {name: "shen"}
console.log('obj2:', obj2) // obj2: {name: "shenzhiyong"}
优点:简单明了,方便记忆
缺点:无法实现对象中方法的深拷贝。看下面代码。
var obj1 = {
name: 'shen',
show: function (argument) {
console.log(1)
}
}
var obj2 = JSON.parse(JSON.stringify(obj1))
console.log('obj1:', obj1) // obj1: {name: "shen", show: ƒ}
console.log('obj2:', obj2) // obj2: {name: "shen"}
2. 手写递归方法
function deepCopy(obj) {
var newobj = obj.constructor === Array ? [] : {};
if (typeof obj !== 'object') {
return obj;
} else {
for (var i in obj) {
if (typeof obj[i] === 'object'){ //判断对象的这条属性是否为对象
newobj[i] = deepCopy(obj[i]); //若是对象进行嵌套调用
}else{
newobj[i] = obj[i];
}
}
}
return newobj; //返回深度克隆后的对象
}
var obj1 = {
name: 'shen',
show: function (argument) {
console.log(1)
}
}
var obj2 = deepCopy(obj1)
console.log('obj1:', obj1) // obj1: {name: "shen", show: ƒ}
console.log('obj2:', obj2) // obj2: {name: "shen"}
优点:能够实现对象和数组的深拷贝
缺点:如果拷贝的对象嵌套过深的话,会对性能有一定的消耗
3. 第三方库 jQuery.extend 和 lodash
$.extend( true, object1, object2 ); // 深度拷贝
$.extend( object1, object2 ); // 浅拷贝
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]); // => false
4. es6解析结构 「…」
var obj1 = {
name: 'shen',
show: function (argument) {
console.log(1)
}
}
var obj2 = { ...obj1 }
obj2.name = 'shenzhiyong'
console.log('obj1:', obj1) // obj {name: "szy", show: ƒ}
console.log('obj2:', obj2) // obj2 {name: "shenzhiyong", show: ƒ}
5. Object.assign()
Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
语法
Object.assign(target, ...sources);
参数:
target: 目标对象
sources: 源对象
返回值:
*目标对象
案例:
var obj1 = {
name: 'shen',
show: function (argument) {
console.log(1)
}
}
var obj2 = Object.assign({} ,obj1) // 一定要写target
obj2.name = 'shenzhiyong'
console.log('obj1:', obj1) // obj {name: "szy", show: ƒ}
console.log('obj2:', obj2) // obj2 {name: "shenzhiyong", show: ƒ}
注意:
对于Object.assign()而言,如果对象的属性值为简单类型(string,number),通过Object.assign({},srcobj);得到的新对象为深拷贝;
如果属性值为对象或其他引用类型,那对于这个对象而言其实是浅拷贝的,这是Object.assign()特别需要注意的地方;
对象只有一级属性为深拷贝,二级属性后就是浅拷贝。
6. 数组中的slice() & concat()
var arr1 = [1,2,3]
var arr2 = arr1.slice() // 方法一
// var arr2 = arr1.concat() //方法二
arr2.push(4)
console.log('arr1:', arr1) // arr1: [1, 2, 3]
console.log('arr2:', arr2) // arr1: [1, 2, 3, 4]
注意:
数组中元素为一维是深拷贝,二维后就是浅拷贝。