1. 浅拷贝
创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
简单来说:浅拷贝只拷贝了对象第一层属性的基本类型值,以及第一层的引用地址。
常见的浅拷贝场景:
Object.assign()
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. 总结
– | 和原数据是否指向同一对象 | 第一层数据为基本数据类型 | 原数据中包含子对象 |
---|---|---|---|
赋值 | 是 | 改变会使原数据一同改变 | 改变会使原数据一同改变 |
浅拷贝 | 否 | 改变不会使原数据一同改变 | 改变会使原数据一同改变 |
深拷贝 | 否 | 改变不会使原数据一同改变 | 改变不会使原数据一同改变 |