js-17-对数组、对象进行浅拷贝和深拷贝


自己总结的一些方法,可能有不到位的地方,欢迎指出

数组

一、浅拷贝

1. 展开运算符…

let arr1 = [1,2,'3',true, { name: '李华'}]
let arr2 = [...arr1] // arr2=[1,2,'3',true, { name: '李华'}]

arr2[0] = 0 // 修改浅拷贝数组中的基本类型元素,原始数组不受影响
arr2[3] = false // 修改浅拷贝数组中的基本类型元素,原始数组不受影响
arr2[4].name = '小帅' // 修改浅拷贝数组中的对象的属性,由于对象是引用类型,所以原始数组中的对象也会受到影响

console.log(arr1) // [1,2,'3',true, { name: '小帅'}]
console.log(arr2) // [0,2,'3',false,{ name: '小帅'}]

2. Array.prototype.slice()

let arr1 = [1, 2, '3', true, { name: '李华'}]
let arr2 = arr1.slice() // arr2=[1,2,'3',true,{ name: '李华'}]

arr2[0] = 0
arr2[3] = false
arr2[4].name = '小帅'

console.log(arr1) // [1, 2, '3', true, { name: '小帅' }]
console.log(arr2) // [0, 2, '3', false, { name: '小帅' }]

二、深拷贝

1. JSON方法

注意:此方法不能处理函数、undefined、Symbol和循环引用

    let arr1 = [1, 2, '3', true, { name: '李华'}]
    let arr2 = JSON.parse(JSON.stringify(arr1))
    
    arr2[0] = 0
    arr2[3] = false
    arr2[4].name = '小帅'
    
    console.log(arr1) // [1, 2, '3', true, { name: '李华'}]
    console.log(arr2) // [0, 2, '3', false, { name: '小帅'}]

2. 递归函数

    function deepClone(obj, hash = new WeakMap()) {
      if (obj === null) return null
      if (obj instanceof Date) return new Date(obj) // 如果是日期对象,则直接返回一个新的日期对象
      if (obj instanceof RegExp) return new RegExp(obj) // 如果是正则对象,则直接返回一个新的正则对象
      // 如果循环引用了就用 weakMap 来解决  
      if (hash.has(obj)) return hash.get(obj);

      let allDesc = Object.getOwnPropertyDescriptors(obj);
      let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc);
      hash.set(obj, cloneObj);

      for (let key of Reflect.ownKeys(obj)) {
        if (typeof obj[key] === 'object' && obj[key] !== null) {
          cloneObj[key] = deepClone(obj[key], hash); // 递归复制  
        } else {
          cloneObj[key] = obj[key];
        }
      }
      return cloneObj;
    }

    let arr1 = [1, 2, '3', true, { name: '李华' }, undefined]
    let arr2 = deepClone(arr1)
    arr2[4].name = '小帅'
    
    console.log(arr1) // [1, 2, '3', true, { name: '李华' }, undefined]
    console.log(arr2) // [1, 2, '3', true, { name: '小帅' }, undefined]

对象

一、浅拷贝

1. Object.assign()

    let obj1 = {
      a: 1, 
      b: {
        c: 2
      }
    }
    let obj2 = Object.assign({}, obj1) // obj2={a:1, b: {c:2}}
    
    obj2.a = 100
    obj2.b.c = 200
    
    console.log(obj1) // { a: 1, b: { c: 200 } }
    console.log(obj2) // { a: 100, b: { c: 200 } }

2. 展开运算符…

    let obj1 = {
      a: 1, 
      b: {
        c: 2
      }
    }
    let obj2 = {...obj1}
    
    obj2.a = 100
    obj2.b.c = 200
    
    console.log(obj1) // { a: 1, b: { c: 200 } }
    console.log(obj2) // { a: 100, b: { c: 200 } }

二、深拷贝

1. JSON方法

    let obj1 = {
      a: 1,
      b: {
        c: 2
      },
      d: [3, 4],
      e: undefined, // 注意此方法undefined不会被复制
      f: function(){ console.log('Hello world')} // 注意此方法函数不会被复制
    }
    let obj2 = JSON.parse(JSON.stringify(obj1))
    
    // console.log(obj2) // {a:1, b: {c:2}, d: [3,4]}
    
    obj2.b.c = 200
    obj2.d[0] = 300
    
    console.log(obj1) // { a: 1, b: { c: 2 }, d: [3, 4], e: undefined, f: f()}
    console.log(obj2) // { a: 1, b: { c: 200 }, d: [300, 4] }

2. 递归函数

    function deepClone(obj, hash = new WeakMap()) {
      // 处理基本数据类型和null  
      if (obj === null || typeof obj !== 'object') {
        return obj;
      }

      // 处理日期和正则对象  
      if (obj instanceof Date) {
        return new Date(obj);
      }
      if (obj instanceof RegExp) {
        return new RegExp(obj);
      }

      // 如果已经处理过这个对象,则直接返回缓存的结果  
      if (hash.has(obj)) {
        return hash.get(obj);
      }

      // 根据obj的类型创建一个新的对象或数组  
      let cloneObj = Array.isArray(obj) ? [] : {};
      hash.set(obj, cloneObj); // 将原始对象和克隆对象存储在hash中,以处理循环引用  

      // 递归复制对象的每个属性  
      for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
          cloneObj[key] = deepClone(obj[key], hash);
        }
      }

      // 如果obj是Map或Set,则需要特殊处理  
      if (obj instanceof Map) {
        cloneObj = new Map();
        obj.forEach((value, key) => {
          cloneObj.set(deepClone(key, hash), deepClone(value, hash));
        });
      } else if (obj instanceof Set) {
        cloneObj = new Set();
        obj.forEach(value => {
          cloneObj.add(deepClone(value, hash));
        });
      }

      return cloneObj;
    }

    let obj1 = {
      a: 1,
      b: {
        c: 2
      },
      d: [3, 4],
      e: undefined, // 注意此方法undefined不会被复制
      f: function () { console.log('Hello world') } // 注意此方法函数不会被复制,而且其实通常不深拷贝函数
    }
    let obj2 = deepClone(obj1)
    // console.log(obj2) // { a: 1, b: { c: 2 }, d:[3, 4], e:undefined, f:f()}
    obj2.b.c = 200
    obj2.d[0] = 300
    console.log(obj1) // { a: 1, b: { c: 2 }, d: [3, 4], e: undefined, f: f()}
    console.log(obj2) // { a: 1, b: { c: 200 }, d: [300, 4], e: undefined, f: f() }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值