如果不是面试需求,不想深究原理,只为了业务。那直接复制如下代码就可以实现简单的深拷贝
JSON.parse(JSON.stringify(copyObj))
stringify() 方法可以将一个JS对象序列化一个JSON字符串,parse()方法可以将JSON字符串反序列化为一个JS对象。通过这两个方法可以实现对象的深拷贝。
利用上述代码做深拷贝存在2个缺点:
理解JS里的引用类型和值类型的区别,知道Obj存储的只是引用。
var a = 100;
var b = a;
a = 200;
console.log(a, b); // 200, 100
每个变量都会保存各自的值,不会相互影响。
var a = {age:20};
b = a;
b.age = 21;
console.log(a.age); // 21
值类型和引用类型的区别:
从内存中来说,值类型是把一个值都存成一个变量类型的位置,如a是100,b赋值成a,这时b的位置又被赋值成了100。修改a位置的值不会影响到b的位置。
引用类型,a赋值给一个对象,a内存的对象通过指针指向这个对象, b赋值给a之后,a和b同时指向这一个对象。{age:20}这个对象只有一份,只不过a和b同时指向这个对象。
引用类型:对象,数组和函数( 引用类型都是可以无限赋值属性的 )
var a = { x: 1 }
var b = a
console.log(a.x, b.x) // 1, 1
a.x = 2
console.log(a.x, b.x) // 2, 2 ;{x:1}这个对象只有一份,只不过a和b同时指向这个对象。
a = { x: 3 } // 直接改变了a指向的对象
console.log(a.x, b.x) // 3, 2
var c = 3;
var d = c
console.log( c, d) // 3, 3
c =4
console.log( c, d) // 4, 3
只有对象里嵌套对象的情况下,才会根据需求讨论,我们要深拷贝还是浅拷贝。
比如:
var a = {
x: 1,
y: 2,
z: 3
}
只有在有嵌套的对象时,深拷贝和浅拷贝才有区别
拷贝后对象的引用,指向了相同的内存空间。
obj2是浅拷贝obj1生成的,虽然obj1和obj2是两个对象了,但obj1和obj2上的属性是===的。
var obj2 = shallowCopy( obj1 , {})
console.log( obj1 !== obj2 )// true
// 无论哪种拷贝,obj1和obj2一定都是2个不同的对象(内存空间不同)
console.log( obj2.arr === obj1.arr )// true
// 他们2个对象里arr的引用,指向【相同的】内存空间
obj2拷贝obj1所有的属性,而且obj2.arr和obj1.arr是指向不同的内存空间。
深拷贝后,除了拷贝了一样的属性,没有任何其他关联。
var obj2 = deepCopy( obj1 , {})
console.log( obj1 !== obj2 ) // true
// 无论哪种拷贝,obj1和obj2一定都是2个不同的对象(内存空间不同)
console.log( obj2.arr === obj1.arr ) // false
// 他们2个对象里arr的引用,指向【不同的】内存空间
点击一列,编辑该列的信息。在弹出的编辑弹出框中,需要复制现有的列信息内容。一般这个值就是一个对象。如果使用了浅拷贝,在弹出框中编辑对象的属性,就会引起原有列信息的变动,因为指向了同一个对象。所以在类似业务场景中,必须使用深拷贝。
// 表格对象的数据结构
var tableArr = [
{goods_name : 'aaa' , code : 'M216C239E0864' , num : '2'},
{goods_name : 'bbb' , code : 'M216C240B0170' , num : '3'},
{goods_name : 'ccc' , code : 'M216D241C04106' , num : '3'},
]
var adjustTableArr = [] // 编辑弹出框的数组
for (var key in tableArr) {
// 简单浅拷贝
adjustTableArr[key] = tableArr[key]
}
// 结论:发现编辑弹出框数据adjustTableArr和原有tableArr的属性随动
浅拷贝比较简单,就是用for in 循环赋值
function shallowCopy(source, target = {}) {
var key;
for (key in source) {
if (source.hasOwnProperty(key)) {
// 可选:原型链不拷贝,__proto__上面的属性
target[key] = source[key];
}
}
return target;
}
function deepCopy (source) {
// 判断source是数组还是对象,选定容器
let target = Array.isArray(source) ? [] : {}
for (let key in source) {
if (typeof (source[key]) === 'object') {
// 如果这一项是object类型,就递归调用deepCopy
target[key] = Array.isArray(source[key]) ? [] : {}
deepCopy(source[key], target[key])
} else {
// 如果不是object类型,就直接赋值拷贝
target[key] = source[key]
}
}
return target
}