js-17-对数组、对象进行浅拷贝和深拷贝
目录
- 数组
- 一、浅拷贝
- 1. 展开运算符...
- 2. Array.prototype.slice()
- 二、深拷贝
- 1. JSON方法
- 2. 递归函数
- 对象
- 一、浅拷贝
- 1. Object.assign()
- 2. 展开运算符...
- 二、深拷贝
- 1. JSON方法
- 2. 递归函数
自己总结的一些方法,可能有不到位的地方,欢迎指出
数组
一、浅拷贝
1. 展开运算符…
let arr1 = [1,2,'3',true, { name: '李华'}]
let arr2 = [...arr1] // arr2=[1,2,'3',true, { name: '李华'}]
arr2[0] = 0 // 修改浅拷贝数组中的基本类型元素,原始数组不受影响
arr2[3] = false // 修改浅拷贝数组中的基本类型元素,原始数组不受影响
arr2[4].name = '小帅' // 修改浅拷贝数组中的对象的属性,由于对象是引用类型,所以原始数组中的对象也会受到影响
console.log(arr1) // [1,2,'3',true, { name: '小帅'}]
console.log(arr2) // [0,2,'3',false,{ name: '小帅'}]
2. Array.prototype.slice()
let arr1 = [1, 2, '3', true, { name: '李华'}]
let arr2 = arr1.slice() // arr2=[1,2,'3',true,{ name: '李华'}]
arr2[0] = 0
arr2[3] = false
arr2[4].name = '小帅'
console.log(arr1) // [1, 2, '3', true, { name: '小帅' }]
console.log(arr2) // [0, 2, '3', false, { name: '小帅' }]
二、深拷贝
1. JSON方法
注意:此方法不能处理函数、undefined、Symbol和循环引用
let arr1 = [1, 2, '3', true, { name: '李华'}]
let arr2 = JSON.parse(JSON.stringify(arr1))
arr2[0] = 0
arr2[3] = false
arr2[4].name = '小帅'
console.log(arr1) // [1, 2, '3', true, { name: '李华'}]
console.log(arr2) // [0, 2, '3', false, { name: '小帅'}]
2. 递归函数
function deepClone(obj, hash = new WeakMap()) {
if (obj === null) return null
if (obj instanceof Date) return new Date(obj) // 如果是日期对象,则直接返回一个新的日期对象
if (obj instanceof RegExp) return new RegExp(obj) // 如果是正则对象,则直接返回一个新的正则对象
// 如果循环引用了就用 weakMap 来解决
if (hash.has(obj)) return hash.get(obj);
let allDesc = Object.getOwnPropertyDescriptors(obj);
let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc);
hash.set(obj, cloneObj);
for (let key of Reflect.ownKeys(obj)) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
cloneObj[key] = deepClone(obj[key], hash); // 递归复制
} else {
cloneObj[key] = obj[key];
}
}
return cloneObj;
}
let arr1 = [1, 2, '3', true, { name: '李华' }, undefined]
let arr2 = deepClone(arr1)
arr2[4].name = '小帅'
console.log(arr1) // [1, 2, '3', true, { name: '李华' }, undefined]
console.log(arr2) // [1, 2, '3', true, { name: '小帅' }, undefined]
对象
一、浅拷贝
1. Object.assign()
let obj1 = {
a: 1,
b: {
c: 2
}
}
let obj2 = Object.assign({}, obj1) // obj2={a:1, b: {c:2}}
obj2.a = 100
obj2.b.c = 200
console.log(obj1) // { a: 1, b: { c: 200 } }
console.log(obj2) // { a: 100, b: { c: 200 } }
2. 展开运算符…
let obj1 = {
a: 1,
b: {
c: 2
}
}
let obj2 = {...obj1}
obj2.a = 100
obj2.b.c = 200
console.log(obj1) // { a: 1, b: { c: 200 } }
console.log(obj2) // { a: 100, b: { c: 200 } }
二、深拷贝
1. JSON方法
let obj1 = {
a: 1,
b: {
c: 2
},
d: [3, 4],
e: undefined, // 注意此方法undefined不会被复制
f: function(){ console.log('Hello world')} // 注意此方法函数不会被复制
}
let obj2 = JSON.parse(JSON.stringify(obj1))
// console.log(obj2) // {a:1, b: {c:2}, d: [3,4]}
obj2.b.c = 200
obj2.d[0] = 300
console.log(obj1) // { a: 1, b: { c: 2 }, d: [3, 4], e: undefined, f: f()}
console.log(obj2) // { a: 1, b: { c: 200 }, d: [300, 4] }
2. 递归函数
function deepClone(obj, hash = new WeakMap()) {
// 处理基本数据类型和null
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 处理日期和正则对象
if (obj instanceof Date) {
return new Date(obj);
}
if (obj instanceof RegExp) {
return new RegExp(obj);
}
// 如果已经处理过这个对象,则直接返回缓存的结果
if (hash.has(obj)) {
return hash.get(obj);
}
// 根据obj的类型创建一个新的对象或数组
let cloneObj = Array.isArray(obj) ? [] : {};
hash.set(obj, cloneObj); // 将原始对象和克隆对象存储在hash中,以处理循环引用
// 递归复制对象的每个属性
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key], hash);
}
}
// 如果obj是Map或Set,则需要特殊处理
if (obj instanceof Map) {
cloneObj = new Map();
obj.forEach((value, key) => {
cloneObj.set(deepClone(key, hash), deepClone(value, hash));
});
} else if (obj instanceof Set) {
cloneObj = new Set();
obj.forEach(value => {
cloneObj.add(deepClone(value, hash));
});
}
return cloneObj;
}
let obj1 = {
a: 1,
b: {
c: 2
},
d: [3, 4],
e: undefined, // 注意此方法undefined不会被复制
f: function () { console.log('Hello world') } // 注意此方法函数不会被复制,而且其实通常不深拷贝函数
}
let obj2 = deepClone(obj1)
// console.log(obj2) // { a: 1, b: { c: 2 }, d:[3, 4], e:undefined, f:f()}
obj2.b.c = 200
obj2.d[0] = 300
console.log(obj1) // { a: 1, b: { c: 2 }, d: [3, 4], e: undefined, f: f()}
console.log(obj2) // { a: 1, b: { c: 200 }, d: [300, 4], e: undefined, f: f() }