跳至主要內容

数据克隆

wzCoding大约 2 分钟综合知识数据克隆

数据克隆

数据克隆(数据拷贝)是我们在开发当中经常会遇到的需求,它可以对原始数据(通常是引用类型的数据)进行复制,得到一份与原始数据相同的 ‘复制体’ ,从而可以让我们放心大胆的对这个 复制体 进行各种操作而不用担心更改原始数据的结构,大大方便了我们的开发工作。

数据克隆有两种形式:

  • 浅层克隆(浅拷贝):浅层克隆只会复制对象的顶层属性。如果对象的属性值是对象或者数组(引用类型),那么浅克隆会复制这个属性的引用,而不是创建一个新的对象或者数组。这表示如果你改变了克隆对象中的一个对象或数组属性,原始对象中的对应属性也会被改变。
  • 深层克隆(深拷贝):深层克隆不仅会复制对象的顶层属性,还会递归地复制所有的子对象和数组。这表示克隆的对象和原始对象在内存中是完全独立的,改变克隆对象不会影响到原始对象。

浅层克隆

在 JS 中,实现浅层克隆的方式有以下几种:

  • Object.assign()
    let obj = { a: 1, b: 2, c:{ a:1 } };
    let clone = Object.assign({}, obj);
    console.log(clone)  // { a: 1, b: 2, c:{ a:1 } }
    console.log(clone.c === obj.c)  // true
    
  • 扩展运算符(…)
    let obj = { a: 1, b: 2, c:{ a:1 } };
    let clone = {...obj}
    console.log(clone)  // { a: 1, b: 2, c:{ a:1 } }
    console.log(clone.c === obj.c)  // true
    
  • Array.prototype.slice()
    let arr = [1, 2, 3, { a:1 }];
    let clone = arr.silce();
    console.log(clone)  // [1, 2, 3, { a:1 }]
    console.log(clone[3] === arr[3])  // true
    

深层克隆

在 JS 中,实现深层克隆的方法有以下几种:

  • JSON.parse() 和 JSON.stringify()
    let obj = { a: 1, b: { c: 2 } };
    let clone = JSON.parse(JSON.stringify(obj));
    console.log(clone); // { a: 1, b: { c: 2 } }
    console.log(clone.b === obj.b)  // false
    
  • structuredClone()
     let obj = { a: 1, b: { c: 2 } };
     let clone = JSON.parse(JSON.stringify(obj));
     console.log(clone); // { a: 1, b: { c: 2 } }
     console.log(clone.b === obj.b)  // false
    
  • 递归实现
     function deepClone(target, cache = new WeakMap()) {
        if (target == null || typeof target !== 'object') {
           return target
        }
        // 检查是否存在缓存,有缓存则直接使用缓存
        if (cache.has(target)) {
           return cache.get(target)
        }
        let clone = Array.isArray(target) ? [] : {}
        //设置克隆对象的原型与原始数据的原型保持一致
        Object.setPrototypeOf(clone, Object.getPrototypeOf(target))
        cache.set(target, clone)
        // 递归复制属性
        for (let key in target) {
           if (target.hasOwnProperty(key)) {
                 clone[key] = deepClone(target[key], cache)
           }
        }
    
        return clone
     }
    
     let obj = { a: 1, b: { c: 2 } };
     let clone = deepClone(obj);
     console.log(clone); // { a: 1, b: { c: 2 } }
     console.log(clone.b === obj.b)  // false
    
ℹ️提示

JSON.parse() 和 JSON.stringify() 无法处理原始对象中存在循环引用的情况