JavaScript中对象的深复制
参考资料:
要理解 JS 对象的深浅复制,首先需要理解:
- JS 中数据类型分为基本类型和引用类型;
- 基本类型的比较(赋值)是值的比较(赋值)
- 引用类型的比较(赋值)是引用的比较(赋值)
有了上面的基础,再来讨论对象深浅复制。
基本复制
let me = { name: "zyh", age: "24"};
let meCloned_1 = me;
let meCloned_2 = Object(me);
console.log(me === meCloned_1); // expect true
console.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 false
console.log(obj.o === objCloned.o); // expect true
console.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 false
console.log(obj.o === objCloned.o); // expect true
console.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 false
console.log(obj.o === objCloned.o); // expect false
console.log(obj.arr === objCloned.arr); // expect false
console.log(objCloned);