文章目录加载中
JavaScript基础-深浅拷贝
实现一个对象的深拷贝函数,需要考虑对象的元素类型以及对应的解决方案:
- 基础类型:这种最简单,直接赋值即可
- 对象类型:递归调用拷贝函数
- 数组类型:这种最难,因为数组中的元素可能是基础类型、对象还可能数组,因此要专门做一个函数来处理数组的深拷贝
/**
* 数组的深拷贝函数
* @param {Array} src
* @param {Array} target
*/
function cloneArr(src, target) {
for (let item of src) {
if (Array.isArray(item)) {
target.push(cloneArr(item, []));
} else if (typeof item === "object") {
target.push(deepClone(item, {}));
} else {
target.push(item);
}
}
return target;
}
/**
* 对象的深拷贝实现
* @param {Object} src
* @param {Object} target
* @return {Object}
*/
function deepClone(src, target) {
const keys = Reflect.ownKeys(src);
let value = null;
for (let key of keys) {
value = src[key];
if (Array.isArray(value)) {
target[key] = cloneArr(value, []);
} else if (typeof value === "object") {
// 如果是对象而且不是数组, 那么递归调用深拷贝
target[key] = deepClone(value, {});
} else {
target[key] = value;
}
}
return target;
}
这段代码是不是比网上看到的多了很多?因为考虑很周全,请看下面的测试用例:
// 这个对象a是一个囊括以上所有情况的对象
let a = {
age: 1,
jobs: {
first: "FE"
},
schools: [
{
name: "shenda"
},
{
name: "shiyan"
}
],
arr: [
[
{
value: "1"
}
],
[
{
value: "2"
}
]
]
};
let b = {};
deepClone(a, b);
a.jobs.first = "native";
a.schools[0].name = "SZU";
a.arr[0][0].value = "100";
console.log(a.jobs.first, b.jobs.first); // output: native FE
console.log(a.schools[0], b.schools[0]); // output: { name: 'SZU' } { name: 'shenda' }
console.log(a.arr[0][0].value, b.arr[0][0].value); // output: 100 1
console.log(Array.isArray(a.arr[0])); // output: true
看到测试用例,应该会有人奇怪为什么最后要输出Array.isArray(a.arr[0])
。这主要是因为网上很多实现方法没有针对 array 做处理,直接将其当成 object,这样拷贝后虽然值没问题,但是 array 的元素会被转化为 object。这显然是错误的做法。
而上面所说的深拷贝函数就解决了这个问题。
本文来自心谭博客:xin-tan.com,经常更新web和算法的文章笔记,前往github查看目录归纳:github.com/dongyuanxin/blog
0