JavaScript中对象的深复制
参考资料:
要理解 JS 对象的深浅复制,首先需要理解:
- JS 中数据类型分为基本类型和引用类型;
- 基本类型的比较(赋值)是值的比较(赋值)
- 引用类型的比较(赋值)是引用的比较(赋值)
有了上面的基础,再来讨论对象深浅复制。
基本复制
let me = { name: "zyh", age: "24"};let meCloned_1 = me;let meCloned_2 = Object(me);console.log(me === meCloned_1); // expect trueconsole.log(me === meCloned_2); // expect true
最基本的复制实际只是实现了引用地址的复制
浅复制
let obj = {o: {count: 9,name: "haha",},num: 34,str: "xixi",arr: [3, 9],}// let objCloned = deepClone({},obj);let objCloned = Object.assign({}, obj);console.log(obj === objCloned); // expect falseconsole.log(obj.o === objCloned.o); // expect trueconsole.log(obj.arr === objCloned.arr); // expect true
可以看出来ES6的Object.assign()只能实现对象的浅复制。
ES6 Object.assign() 的实现原理如下 deepClone() 函数:
// ES6 Object.assign() 的实现原理如下 deepClone() 函数function deepClone(target, varArgs) {if (target === null) {throw new TypeError("Cannot convert undefined or null to object");}let result = Object(target);for (let i = 1; i < arguments.length; i++) {let nextSource = arguments[i];if (nextSource !== null) {for (let nextKey in nextSource) {if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {result[nextKey] = nextSource[nextKey];}}}}return result;}let objCloned = deepClone({},obj);console.log(obj === objCloned); // expect falseconsole.log(obj.o === objCloned.o); // expect trueconsole.log(obj.arr === objCloned.arr); // expect true
参考资料:MDN: Object.assign()
深复制
各种深复制方法都存在局限性,没有最好,只有更好
下面是个人实现的深复制函数,仅适用于处理属性值为object和array类型的数据,较为简单,仅供参考
//let deepClone = function (obj) {if (obj === null) {throw new TypeError("Cannot convert null to object")}let result = {};let flag = Object.prototype.toString.call(obj);if (flag === "[object Object]") {for (let key in obj) {if (Object.prototype.hasOwnProperty.call(obj, key)) {let keyFlag = Object.prototype.toString.call(obj[key]);if (["[object Object]", "[object Array]"].includes(keyFlag)) {result[key] = deepClone(obj[key]);} else {result[key] = obj[key];}}}} else if (flag === "[object Array]") {result = Array.prototype.map.call(obj, ele => ele);} else {result = obj;}return result;}let objCloned = deepClone(obj);console.log(obj === objCloned); // expect falseconsole.log(obj.o === objCloned.o); // expect falseconsole.log(obj.arr === objCloned.arr); // expect falseconsole.log(objCloned);
