1. 浅拷贝
创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
简单来说:浅拷贝只拷贝了对象第一层属性的基本类型值,以及第一层的引用地址。
常见的浅拷贝场景:
let a = {
name: "book",
book: {
price: "45"
}
}
let b = Object.assign({}, a);
a.name = "change";
a.book.price = "55";
console.log(a); // {name: "change", book: { price: 55 }}
console.log(b); // {name: "book", book: { price: 55 }}
-
展开语法 Spread
let a = {
name: "book",
book: {
price: "45"
}
}
let b = {...a}
a.name = "change";
a.book.price = "55";
console.log(a); // {name: "change", book: { price: 55 }}
console.log(b); // {name: "book", book: { price: 55 }}
-
Array.prototype.slice()
let a = [0, "1", [2, 3]];
let b = a.slice(1);
console.log(b);
// ["1", [2, 3]]
a[1] = "99";
a[2][0] = 4;
console.log(a);
// [0, "99", [4, 3]]
console.log(b);
// ["1", [4, 3]]
2. 深拷贝
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响。
常见的深拷贝场景:
-
JSON.parse(JSON.stringify(object))
虽然这种方法,做深拷贝的时候比较简单,但是会有以下几个问题:
1、会忽略 undefined
2、会忽略 symbol
3、不能序列化函数
4、不能解决循环引用的对象
5、不能正确处理new Date()
6、不能处理正则
-
undefined
、symbol
和函数这三种情况,会直接忽略。(因为这三种值不是有效的JSON值,在JSON.stringify的时候会被忽略)。
let obj = {
name: 'book',
a: undefined,
b: Symbol('muyiy'),
c: function() {}
}
console.log(obj);
// {
// name: "muyiy",
// a: undefined,
// b: Symbol(muyiy),
// c: ƒ ()
// }
let b = JSON.parse(JSON.stringify(obj));
console.log(b);
// {name: "book"}
-
循环引用情况下,会报错。
let obj = {
a: 1,
b: {
c: 2,
d: 3
}
}
obj.a = obj.b;
obj.b.c = obj.a;
let b = JSON.parse(JSON.stringify(obj));
// Uncaught TypeError: Converting circular structure to JSON
-
new Date
情况下,转换结果不正确。
new Date();
// Mon Dec 24 2018 10:59:14 GMT+0800 (China Standard Time)
JSON.stringify(new Date());
// ""2018-12-24T02:59:25.776Z""
JSON.parse(JSON.stringify(new Date()));
// "2018-12-24T02:59:41.523Z"
-
正则情况下,
let obj = {
name: "muyiy",
a: /'123'/
}
console.log(obj);
// {name: "muyiy", a: /'123'/}
let b = JSON.parse(JSON.stringify(obj));
console.log(b);
// {name: "muyiy", a: {}}
-
-
jQuery.extend() 和 lodash.cloneDeep()
3. 总结
– |
和原数据是否指向同一对象 |
第一层数据为基本数据类型 |
原数据中包含子对象 |
赋值 |
是 |
改变会使原数据一同改变 |
改变会使原数据一同改变 |
浅拷贝 |
否 |
改变不会使原数据一同改变 |
改变会使原数据一同改变 |
深拷贝 |
否 |
改变不会使原数据一同改变 |
改变不会使原数据一同改变 |