Js克隆对象
1 浅复制
具体方法
js
// 数组
Array.prototype.slice
const oldArr = new Array(100).fill(null).map(() => Math.random() * 100 | 0)
const newArr = oldArr.slice()
// 普通对象
Object.assign
const oldObj = new Object() // plain object
const newObj = Object.assign({}, oldObj)
2 深复制
1) 转字符串再还原
js
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj))
}
2) 便利对象,递归克隆
js
function deepClone(obj) {
if ( typeof obj !== 'object' ) {
return obj
}
const ret = Array.isArray(obj) ? [] : {}
for ( let i in obj ) {
ret[i] = deepClone(obj[i])
}
return ret
}
3)循环引用对象
如果采用以上两种克隆方式,遇到循环引用对象会导致报错
js
function updateClone(obj) {
const map = new Map();
function deepClone(obj) {
if (typeof obj !== 'object') {
return obj;
}
const ret = Array.isArray(obj) ? [] : {};
for (let i in obj) {
const dist = obj[i];
if (map.has(dist)) {
continue;
} else {
map.set(dist, true);
ret[i] = dist;
}
}
return ret;
}
return deepClone(obj);
}
4)难克隆对象,甚至无法克隆对象
比如Date, Function, Error或者自定义的一些class构造对象
js
const oldDate = new Date()
const newDate = new Date(+oldDate)
// Date可以处理
// Function 使用toString,但是考虑到可能bind有些context,而且函数的作用域链,这些没法搞
// Error stack message这些也没法处理
// Window构造对象这些更是无法处理
5)对象属性key异常情况
属性不可枚举
js
Object.getOwnPropertyDescriptors({a:1})

这个可以通过使用Object.getOwnPropertyNames
获取,但是赋值的时候得注意一下,也应该是enumerable: false
遍历了原型链上属性,方法
某些同学写代码不注意,直接Object.prototype.xx = xx
那么这个数据就是可以枚举的,for in慢的原因也是因为他不止遍历当前对象,他会沿着原型链一直向上找
可以通过hasOwnProperty过滤掉
总结
其实大部分时候只需要能够克隆plain object就行了,太过于复杂的情况无需考虑