1.数组的拷贝(二维数组的拷贝(深拷贝)方法,请看到最后。。。)
//一纬数组,通过slice、concat,Array.from()方法可以实现 var arr1 = [1, 2], arr2 = arr1.slice(); console.log(arr1); //[1, 2] console.log(arr2); //[1, 2] arr2[0] = 3; //修改arr2 console.log(arr1); //[1, 2] console.log(arr2); //[3, 2]
//二维数组,拷贝完之后修改值,会同时改变被拷贝的数组,拷贝失败 var arr1 = [1, 2, [3, 4]], arr2 = arr1.slice(); console.log(arr1); //[1, 2, [3, 4]] console.log(arr2); //[1, 2, [3, 4]] arr2[2][1] = 5; console.log(arr1); //[1, 2, [3, 5]] console.log(arr2); //[1, 2, [3, 5]]
2.对象的一纬(浅)拷贝
//通过object.assign()可实现一纬对象的拷贝 var obj1 = {x: 1, y: 2}, obj2 = Object.assign({}, obj1); console.log(obj1) //{x: 1, y: 2} console.log(obj2) //{x: 1, y: 2} obj2.x = 2; //修改obj2.x console.log(obj1) //{x: 1, y: 2} console.log(obj2) //{x: 2, y: 2} var obj1 = { x: 1, y: { m: 1 } }; var obj2 = Object.assign({}, obj1); console.log(obj1) //{x: 1, y: {m: 1}} console.log(obj2) //{x: 1, y: {m: 1}} obj2.y.m = 2; //修改obj2.y.m obj2.x = 2; //修改obj2.x //结果显示,obj1的一维x对应着没有改变,说明一纬拷贝成功,但是obj1的二维y.m却改变了,说明深拷贝不成功,拷贝成功的结果应该就是前后两个对象完全脱离联系,改变其中一个,另一个没变化才对 console.log(obj1) //{x: 1, y: {m: 2}} console.log(obj2) //{x: 2, y: {m: 2}}
3.对象的深拷贝
//方法一,通过JSON.parse(JSON.stringify(obj)),但是有一定的弊端 //以下是一般情况下的使用 var obj1 = { x: 1, y: { m: 1 } }; var obj2 = JSON.parse(JSON.stringify(obj1)); console.log(obj1) //{x: 1, y: {m: 1}} console.log(obj2) //{x: 1, y: {m: 1}} obj2.y.m = 2; //修改obj2.y.m console.log(obj1) //{x: 1, y: {m: 1}} console.log(obj2) //{x: 2, y: {m: 2}} //以下是会出现问题的使用 var obj1 = { x: 1, y: undefined, z: function add(z1, z2) { return z1 + z2 }, a: Symbol("foo") }; var obj2 = JSON.parse(JSON.stringify(obj1)); console.log(obj1) //{x: 1, y: undefined, z: ƒ, a: Symbol(foo)} console.log(JSON.stringify(obj1)); //{"x":1} console.log(obj2) //{x: 1} //总结:undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。 //方法二(有一定瑕疵的递归),使用递归 function deepCopy(obj) { // 创建一个新对象 let result = {} let keys = Object.keys(obj), key = null, temp = null; for (let i = 0; i < keys.length; i++) { key = keys[i]; temp = obj[key]; // 如果字段的值也是一个对象则递归操作 if (temp && typeof temp === 'object') { result[key] = deepCopy(temp); } else { // 否则直接赋值给新对象 result[key] = temp; } } return result; } var obj1 = { x: { m: 1 }, y: undefined, z: function add(z1, z2) { return z1 + z2 }, a: Symbol("foo") }; var obj2 = deepCopy(obj1); obj2.x.m = 2; console.log(obj1); //{x: {m: 1}, y: undefined, z: ƒ, a: Symbol(foo)} console.log(obj2); //{x: {m: 2}, y: undefined, z: ƒ, a: Symbol(foo)} //方法三(完美方法,同时解决了循环引用的问题)(同时适用于数组,因为数组也是特殊的object) //循环引用的案例 var obj1 = { x: 1, y: 2 }; obj1.z = obj1; var obj2 = deepCopy(obj1); //解决了循环引用的完美深拷贝方法如下: function deepCopy(obj, parent = null) { // 创建一个新对象 let result = {}; let keys = Object.keys(obj), key = null, temp= null, _parent = parent; // 该字段有父级则需要追溯该字段的父级 while (_parent) { // 如果该字段引用了它的父级则为循环引用 if (_parent.originalParent === obj) { // 循环引用直接返回同级的新对象 return _parent.currentParent; } _parent = _parent.parent; } for (let i = 0; i < keys.length; i++) { key = keys[i]; temp= obj[key]; // 如果字段的值也是一个对象 if (temp && typeof temp=== 'object') { // 递归执行深拷贝 将同级的待拷贝对象与新对象传递给 parent 方便追溯循环引用 result[key] = DeepCopy(temp, { originalParent: obj, currentParent: result, parent: parent }); } else { result[key] = temp; } } return result; } var obj1 = { x: 1, y: 2 }; obj1.z = obj1; var obj2 = deepCopy(obj1); console.log(obj1); //太长了去浏览器试一下吧~ console.log(obj2); //太长了去浏览器试一下吧~