Js克隆对象

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就行了,太过于复杂的情况无需考虑