- 什么是深拷贝和浅拷贝:
深拷贝针对的是复杂的 Object 数据类型,深拷贝需要将属性的各个层级都要拷贝过来。
深拷贝将另一个对象的属性值拷贝过来之后,另一个对象的属性值并不受到影响,因为它自己在堆中开辟了自己的内存区域,不受外界干扰。
浅拷贝主要拷贝的是对象的引用值,当改变对象的值,另一个对象的值也会发生变化。
例子:js中的slice() 方法不能达到完全的深拷贝, 一维数组可以深拷贝,当改变a[0]的值后,打印处a的值改变,b的值并不受到影响,仍然是[1,2,3,4]。
换一个多层级的数组://一维数组的slice let a = [1, 2, 3, 4], b = a.slice(); a[0] = 5; console.log(a); //[ 5, 2, 3, 4 ] console.log(b); //[ 1, 2, 3, 4 ] b[0] = 10; console.log(a); //[ 5, 2, 3, 4 ] console.log(b); //[ 10, 2, 3, 4 ]
二维数组中slice() 拷贝并不彻底,二级属性没能拷贝成功,b仍脱离不了a的控制,说明slice不是真正的深拷贝。let a=[0,1,[2,3],4], b = a.slice(); a[0]=2; a[2][0]=1; console.log(a); //[ 2, 1, [ 1, 3 ], 4 ] console.log(b); //[ 0, 1, [ 1, 3 ], 4 ]
同理,concat 方法不是真正的深拷贝,也存在这样的情况。 - 扩展运算符和 Object.assign() 都不是深拷贝
扩展运算符:let outObj = { inobj: { a: 1, b: 2 } } let newObj = { ...outObj } newObj.inobj.a = 2 console.log(outObj); //{ inobj: { a: 2, b: 2 } }
Object.assign():浅拷贝
let outObj = { inObj:{a:1,b:2} } let newObj = Object.assign({},outObj); newObj.inObj.a = 2; console.log(outObj); //{ inObj: { a: 2, b: 2 } }
只有一层嵌套是可以的,所以能否深拷贝要看数据结构怎么设计的。
-
实现深拷贝的三个办法:
JSON.parse(JSON.stringfy()): 这个方法很简单 ,但不能拷贝函数。遇到正则会变成对象。let outObj = { foo: 1, inObj: { a: 1, b: 2 }, bar: function () { } } let newObj = JSON.parse(JSON.stringify(outObj)); console.log(newObj); //{ foo: 1, inObj: { a: 1, b: 2 } } newObj.inObj.a = 2; console.log(outObj); //{ foo: 1, inObj: { a: 1, b: 2 }, bar: [Function: bar] } console.log(newObj) //{ foo: 1, inObj: { a: 2, b: 2 } }
-
用 for...in 遍历和复制实现一个深拷贝方法:
const deepClone = (obj) => { if (typeof obj !== 'object') return let newObj = obj instanceof Array ? [] : {} for (let key in obj) { if (typeof obj[key] === 'object') { newObj[key] = deepClone(obj[key]) } else { newObj[key] = obj[key] } } return newObj }
将上面的例子拿来验一下:
let outObj = { foo: 1, inObj: { a: 1, b: 2 }, bar: function () { } } let objCopy = deepClone(outObj); console.log(objCopy); //{ foo: 1, inObj: { a: 1, b: 2 }, bar: [Function: bar] } objCopy.inObj.a = 2; console.log(objCopy); //{ foo: 1, inObj: { a: 2, b: 2 }, bar: [Function: bar] } console.log(outObj); //{ foo: 1, inObj: { a: 1, b: 2 }, bar: [Function: bar] }
复杂对象的处理:
const allRoomPos = { "幻灵": { 'p1': { 'x': 1000, 'y': 615 }, 'p2': { 'x': 1000, 'y': 670 }, 'p3': { 'x': 935, 'y': 670 }, 'p4': { 'x': 935, 'y': 615 } }, "仙游": { 'p1': { 'x': 1000, 'y': 515 }, 'p2': { 'x': 1000, 'y': 580 }, 'p3': { 'x': 935, 'y': 580 }, 'p4': { 'x': 935, 'y': 515 } }, } let copyRoompos = deepClone(allRoomPos); console.log(copyRoompos); /* { '幻灵': { p1: { x: 1000, y: 615 }, p2: { x: 1000, y: 670 }, p3: { x: 935, y: 670 }, p4: { x: 935, y: 615 } }, '仙游': { p1: { x: 1000, y: 515 }, p2: { x: 1000, y: 580 }, p3: { x: 935, y: 580 }, p4: { x: 935, y: 515 } } } */ console.log(allRoomPos) /* { '幻灵': { p1: { x: 1000, y: 615 }, p2: { x: 1000, y: 670 }, p3: { x: 935, y: 670 }, p4: { x: 935, y: 615 } }, '仙游': { p1: { x: 1000, y: 515 }, p2: { x: 1000, y: 580 }, p3: { x: 935, y: 580 }, p4: { x: 935, y: 515 } } } */
-
利用数组的 Array.prototype.forEach 和 ECMAScript 5 中的Object.* 函数实现深拷贝:
var deepClone = function (obj) { var copy = Object.create(Object.getPrototypeOf(obj)); var propNames = Object.getOwnPropertyNames(obj); propNames.forEach(function (name) { var desc = Object.getOwnPropertyDescriptor(obj, name); Object.defineProperty(copy, name, desc); }); return copy; } var obj1 = { family: { brother: "wangzhipeng", father: "wanglicai", mother: "sunaiyun" }, name: "gino", sex: "male", age: "27" }; var obj2 = deepClone(obj1); obj1.sex = "close"; console.log(obj1); /* { family: { brother: 'wangzhipeng', father: 'wanglicai', mother: 'sunaiyun' }, name: 'gino', sex: 'close', age: '27' } */ console.log(obj2); /* { family: { brother: 'wangzhipeng', father: 'wanglicai', mother: 'sunaiyun' }, name: 'gino', sex: 'male', age: '27' } */
浅拷贝和深拷贝三种方法
于 2020-04-14 20:35:17 首次发布