js拷贝
浅拷贝
Object.assign(target, ...source)
const target = {}
const source = {a: 1, b: {c: 2}}
Object.assign(target, source)
target.a = 3
target.b.c = 4
console.log(target) // { a: 3, b: { c: 4 } }
console.log(source) // { a: 1, b: { c: 4 } }
Object.assign不会拷贝对象的继承属性
Object.assign不会拷贝对象的不可枚举的属性
可以拷贝Symbol类型的属性
扩展运算符 ...
const source = {a: 1, b: {c: 2}};
const target = {...source};
target.a = 3;
target.b.c = 4;
console.log(target); // { a: 3, b: { c: 4 } }
console.log(source); // { a: 1, b: { c: 4 } }
数组的concat方法
let arr = [1, [21, 22]]
let newArr = arr.concat()
newArr[0] = 2
newArr[1][0] = 31
console.log(arr) // [ 1, [ 31, 22 ] ]
console.log(newArr) // [ 2, [ 31, 22 ] ]
只能处理首层数据为数组数据
数组的slice方法
let arr = [1, [21, 22]]
let newArr = arr.concat()
newArr[0] = 2
newArr[1][0] = 31
console.log(arr) // [ 1, [ 31, 22 ] ]
console.log(newArr) // [ 2, [ 31, 22 ] ]
只能处理首层数据为数组的数据
自己实现方法shallowClone
const source = { a: 1, b: {c: 2}, d: undefined, e: null, f: () => {}, g: Symbol(), h: new Date(), i: RegExp(), j: NaN, k: Infinity, l: -Infinity}
const target = JSON.parse(JSON.stringify(source))
console.log(target) // { a: 1, b: { c: 2 }, e: null, h: '2024-12-01T15:09:04.548Z', i: {}, j: NaN, k: Infinity, l: -Infinity}
console.log(source) // { a: 1, b: { c: 2 }, d: undefined, e: null, f: [Function: f], g: Symbol(), h: 2024-12-01T15:09:04.548Z, i: /(?:)/, j: null, k: mull, l: null}
深拷贝
JSON.stringify()
const source = { a: 1, b: {c: 2}, d: undefined, e: null, f: () => {}, g: Symbol(), h: new Date(), i: RegExp(), j: NaN, k: Infinity, l: -Infinity}
const target = JSON.parse(JSON.stringify(source))
console.log(target) // { a: 1, b: { c: 2 }, e: null, h: '2024-12-01T15:09:04.548Z', i: {}, j: NaN, k: Infinity, l: -Infinity}
console.log(source) // { a: 1, b: { c: 2 }, d: undefined, e: null, f: [Function: f], g: Symbol(), h: 2024-12-01T15:09:04.548Z, i: /(?:)/, j: null, k: mull, l: null}
使用JSON.stringify会造成值为undefined,function,Symbol的键值对丢失;值为Date类型的数据会变成字符串;无法拷贝不可枚举属性;无法拷贝对象的原型链;拷贝RegExp类型会变成空对象;对象中含有NaN,Infinity,-Infinity时,对应键的值会转为null;无法拷贝对象的循环应用,即对象成环[obj[key]]=obj
简单深拷贝
let source = {a: 1, b: {c: 2}, d: [1, 2]}
function deepClone(param) {
let cloneParam
// 首先,判断输入的值为对象还是数组还是其他类型
if (checkOfData(param) === 'object') {
cloneParam = {}
// 对象使用for in循环,将对象内的值再进行递归调用
for (let i in param) {
cloneParam[i] = deepClone(param[i])
}
} else if (checkOfData(param) === 'array') {
cloneParam = []
// 数字使用for循环,将数组内的值再进行递归调用
for (let i = 0; i < param.length; i++) {
cloneParam[i] = deepClone(param[i])
}
} else {
// 普通值直接进行赋值
cloneParam = param
}
return cloneParam
}
const target = deepClone(source)
target.b.c = 3
target.d[0] = 4
console.log(target) // { a: 1, b: { c: 3 }, d: [ 4, 2 ] }
console.log(source) // { a: 1, b: { c: 2 }, d: [ 1, 2 ] }
只对对象,数组做处理,其他不做处理
改进版深拷贝
const isComplexDataType = (obj) => (typeof obj === 'object' || typeof obj === 'function') && obj != null
const deepClone = function (obj, hash = new WeakMap()) {
if (obj.constructor === Date) return new Date(obj) // 日期对象返回一个新日期
if (obj.constructor === RegExp) return new RegExp(obj) // 正则对象返回一个新的正则对象
if (hash.has(obj)) return hash.get(obj) // 循环引用就用weakMap来解决
let allDesc = Object.getOwnPropertyDescriptor(obj)
// 遍历出入参数的所有键的特性
let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)
// 继承原型链
hash.set(obj, cloneObj)
for (let key of Reflect.ownKeys(obj)) {
cloneObj[key] =
isComplexDataType(obj[key]) && typeof obj[key] !== 'function'
? deepClone(obj[key], hash)
: obj[key]
}
return cloneObj
}
let source = { a: 1, b: {c: 2}, d: undefined, e: null, f: () => {}, g: Symbol(), h: new Date(), i: RegExp(), j: NaN, k: Infinity, l: -Infinity, [Symbol('1')]: 1}
Object.defineProperty(source, 'innumberable', { enumerable: false, value: '不可枚举属性' })
source = Object.create(source, Object.getOwnPropertyDescriptors(source))
source.loop = source // 设置loop成循环引用的属性
const target = deepClone(source)
target.b.c = 4
console.log(source) // { a: 1, b: { c: 2 }, d: undefined, e: null, f: [Function: f], g: Symbol(), h: 2024-12-03T03:11:20.305Z, i: /(?:)/, j: NaN, k: Infinity, l: -Infinity, loop: [Circular *1], [Symbol(1)]: 1}
console.log(target) // { a: 1, b: { c: 4 }, d: undefined, e: null, f: [Function: f], g: Symbol(), h: 2024-12-03T03:11:20.305Z, i: /(?:)/, j: NaN, k: Infinity, l: -Infinity, loop: [Circular *1], [Symbol(1)]: 1}
支持所有类型拷贝,包括对象成环