JS 深拷贝
需要用到深拷贝的原因,引用类型被修改会导致其他数据被改动,而经常赋值操作希望操作别的数据不要影响自己
Object.assign
可以深拷贝对象的一层属性
...展开运算符
可以深拷贝对象的一层属性
JSON.stringify
可以拷贝对象深层属性,但是会丢失
undefined
symbol
function
js
let a = {
age: undefined,
sex: Symbol('male'),
jobs: function() {},
name: '11'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "11"}
嵌套对象属性会抛错
MessageChannel
可以深拷贝嵌套引用和 undefined
symbol
,但是不能拷贝 function
js
const obj = {
a: undefined,
sex: Symbol('male'),
b: {
c: 2
}
}
obj.b.d = obj.b // 嵌套引用
// 注意该方法是异步的
function deepClone(obj) {
return new Promise(resolve => {
const { port1, port2 } = new MessageChannel()
port2.onmessage = ev => resolve(ev.data)
port1.postMessage(obj)
})
}
// 可以处理 undefined symbol 和嵌套引用对象
const test = async () => {
const clone = await deepClone(obj)
console.log(clone)
}
test()
手写深拷贝-广度优先递归
手写深拷贝-深度优先递归
js
function deepClone(obj) {
function isObject(o) {
return (typeof o === 'object' || typeof o === 'function') && o !== null
}
if (!isObject(obj)) {
throw new Error('非对象') // 非对象通过抛错跳过
}
// 数组类型
let isArray = Array.isArray(obj)
let newObj = isArray ? [...obj] : { ...obj }
// TODO: Reflect.ownKeys
Reflect.ownKeys(newObj).forEach(key => {
// 递归执行自身
newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
})
return newObj
}
let obj = {
a: [1, 2, 3],
b: {
c: 2,
d: 3
}
}
let newObj = deepClone(obj)
newObj.b.c = 1
console.log(obj.b.c) // 2
递归深度判断对象属性是否全等
js
function isObjEqual(obj1, obj2) {
// 获取key
const obj1KeyList = Object.getOwnPropertyNames(obj1);
const obj2KeyList = Object.getOwnPropertyNames(obj2);
// key长度不符,对象不相等
if (obj1KeyList.length !== obj2KeyList.length) {
return false;
}
for (const key of obj1KeyList) {
const obj1Value = obj1[key];
const obj2Value = obj2[key];
if (typeof (obj1Value) === \'object\') {
// 递归
if (!isObjEqual(obj1Value, obj2Value)) {
return false;
}
} else if (obj1Value !== obj2Value) {
return false;
}
}
return true;}console.log(isObjEqual([],[]))