数组拷贝
javascript 原生提供了一些可以实现数组项为原始数据类型的数组的拷贝方法:
(但是这些方法对于数组项为引用类型的数组则不再有效)
Array.prototype.slice 、 Array.prototype.concat 和 Array.from
const arr = [1, 3, 1, 4, 'love', 'you'];
const temp = arr.concat();
const temp1 = arr.slice();
const temp2 = Array.from(arr)
利用对象序列化拷贝对象
一般情况下可以通过 JSON.parse + JSON.stringify 对对象进行拷贝:
const obj = {
boy: 'Jack',
body: {
weight: 80,
height: 185
}
};
const copiedObj = JSON.parse(JSON.stringify(obj));
但是这种方法具有很大的局限性:
- 对象的属性中包含函数、正则、日期对象
- 对象中存在循环引用
/* 属性包含函数、正则、日期对象 */
const obj = {
fn(){ return null },
reg: /sw+/i,
date: new Date()
}
/*
copiedObj = {
date: "2022-09-08T12:52:10.304Z" // 日期对象序列化调用其 toJSON() 方法
reg: {} // reg 对象序列化将被转化为 {}
}
// 函数将被序列化为 undefined
*/
const copiedObj = JSON.parse(JSON.stringify(obj))
/* 存在循环引用的对象 */
const body = {
weight: 80,
height: 185
}
const person = {
name: 'Jack'
};
person.body = body
body.self = person
// 抛出异常: Uncaught TypeError: Converting circular structure to JSON
const copiedPerson = JSON.parse(JSON.stringify(person));
通用深拷贝方法
深度遍历:
const deepCopy = (function () {
function getType(raw) {
return Object.prototype.toString.call(raw).slice(8, -1).toLowerCase();
}
const map = new WeakMap();
return function copy(obj) {
const type = getType(obj);
if (type === "null") return obj;
if (type === "undefined") return obj;
if (type === "function") return obj; // 函数
if (type === "regexp") return obj; // 正则
if (type === "date") return new Date(obj.getTime()); // 日期
if (type === "array") {
if (map.get(obj)) return obj;
map.set(obj, true);
return obj.map((v) => copy(v));
}
if (type === "object") {
if (map.get(obj)) return obj;
map.set(obj, true);
const temp = {};
Object.keys(obj).forEach((k) => {
temp[k] = copy(obj[k]);
});
return temp;
}
return obj;
};
})();