JavaScript中深拷贝实现

JavaScript 中深拷贝实现
 
拷贝时候涉及到:
1、循环结构
2、判断数组 Array 还是对象 Object
 
函数实现
/**
 * 获取满足条件的数组中的第一个元素
 * @param {Array} list 将要筛选的数组
 * @param {Function} f 用来过滤的函数
 */
function find(list, f) {
  return list.filter(f)[0]
}
/**
 * 深拷贝对象,同时考虑到了循环引用的情况
 * 缓存了所有的嵌套对象和它的拷贝
 * 如果检测到循环引用,返回拷贝,防止了无限循环
 * @param {Object} obj 需要拷贝的对象
 * @param {Array} cache 用来判断是否循环引用,存储对象以及对象的拷贝
 */
function deepCopy(obj, cache = []) {
  // 为空或者不是对象则返回原 obj
  if (obj === null || typeof obj !== 'object') {
    return obj
  }

  // 若是循环结构,则返回之前对象的 copy,而不是引用
  const hit = find(cache, c => c.original === obj)
  if (hit) {
    return hit.copy
  }

  const copy = Array.isArray(obj) ? [] : {}
  // 将 copy 放入 cache 中
  // 我们可能在递归中引用 copy
  cache.push({
    original: obj,
    copy
  })

  Object.keys(obj).forEach(key => {
    copy[key] = deepCopy(obj[key], cache)
  })

  return copy
}

 

应用

1、非嵌套例子:
const original = {
  a: 1,
  b: 'string',
  c: true,
  d: null,
  e: undefined
}
const copy = deepCopy(original)
console.log('copy === original :', copy === original) 
// copy === original : false
console.log('copy :', JSON.stringify(copy, null, 2)) 
// copy : {
//     "a": 1,
//     "b": "string",
//     "c": true,
//     "d": null
// }

 

2、嵌套例子: 

const original = {
  a: {
    b: 1,
    c: [
      2,
      3,
      {
        d: 4
      }
    ]
  }
}
const copy = deepCopy(original)
console.log('copy === original :', copy === original)
// copy === original : false
console.log('copy :', JSON.stringify(copy, null, 2))
// copy : {
//     "a": {
//         "b": 1,
//         "c": [
//         2,
//         3,
//         {
//             "d": 4
//         }
//         ]
//     }
// }
 
3、循环引用
const original = {
  a: 1
}
original.circularExample = original

const copy = deepCopy(original)
console.log('copy === original :', copy === original)
// copy === original : false
console.log('copy :', copy)
// 这里循环引用不可使用 JSON.stringify 来转换,会报错
// copy : { a: 1, circularExample: [Circular] }

 

posted @ 2019-06-01 09:47  青S衫%  阅读(853)  评论(0编辑  收藏  举报