Js中的深度赋值和浅层赋值

本文探讨了JavaScript中对象拷贝的两种主要方式——浅拷贝和深拷贝。浅拷贝包括Object.assign()、lodash的clone方法以及使用...操作符和Array.prototype.concat/slice。深拷贝通常通过JSON.parse(JSON.stringify())实现,但存在处理函数和正则的限制,以及对循环引用和undefined的忽略。此外,lodash的cloneDeep和jQuery.extend也可用于深拷贝,其中后者能处理循环引用的对象。手写实现深拷贝需要判断并递归处理复杂数据类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拷贝有个前提,是针对对象的操作,当想复制一个对象的时候,才存在浅拷贝深拷贝之分!
  1. 浅拷贝的实现方式

    1. Object.assign()

      可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。

    2. lodash的clone方法

    3. …操作符

      let obj1 = { name: 'Kobe', address:{x:100,y:100}}
      let obj2= {... obj1}
      obj1.address.x = 200;
      obj1.name = 'wade'
      console.log('obj2',obj2) // obj2 { name: 'Kobe', address: { x: 200, y: 100 } }
      
    4. Array.prototype.concat

      let arr = [1,2,3]; let arr2 = [4,5,6];let arr3 = arr.concat(arr2)

      let arr = [1, 3, {
          username: 'kobe'
          }];
      let arr2 = arr.concat();    
      arr2[2].username = 'wade';
      console.log(arr);
      
    5. Array.prototype.slice

      let arr = [1, 3, {
          username: ' kobe'
          }];
      let arr3 = arr.slice();
      arr3[2].username = 'wade'
      console.log(arr); // [ 1, 3, { username: 'wade' } ]
      
  2. 深拷贝的实现方式

    1. JSON.parse(JSON.stringify())

      可以处理数组和对象的深拷贝,但是不能处理函数和正则,因为这两者基于这两个函数处理后得到的结果不再是正则/函数

      缺点:

      1. 会忽略undefined
      2. 会忽略symbol
      3. 不能序列化函数
      4. 不能解决循环引用的对象
    2. lodash的cloneDeep函数

    3. jQuery.extend函数

    4. 如果所拷贝的对象含有内置对象,但是不包含函数,可以使用messagechannel,可以拷贝undefined和循环引用的对象

      function structuralClone(obj) {
        return new Promise(resolve => {
          const { port1, port2 } = new MessageChannel()
          port2.onmessage = ev => resolve(ev.data)
          port1.postMessage(obj)
        })
      }
      
      var obj = {
        a: 1,
        b: {
          c: 2
        }
      }
      
      obj.b.d = obj.b
      
      // 注意该方法是异步的
      // 可以处理 undefined 和循环引用对象
      const test = async () => {
        const clone = await structuralClone(obj)
        console.log(clone)
      }
      test()
      
  3. 手写浅拷贝:遍历=>直接等号赋值

// 浅拷贝
let obj1 = {
    name : '深深地',
    arr : [1,[2,3],4],
};
let obj3=shallowClone(obj1)

obj3.name = "春娇";
obj3.arr[1] = [5,6,7] ; // 新旧对象还是共享同一块内存

// 这是个浅拷贝的方法
function shallowClone(source) {
    var target = {};
    for(var i in source) {
        if (source.hasOwnProperty(i)) {
            target[i] = source[i];
        }
    }
    return target;
}
console.log('obj1',obj1) // obj1 { name: '深深地', arr: [ 1, [ 5, 6, 7 ], 4 ] }
console.log('obj3',obj3) // obj3 { name: '春娇', arr: [ 1, [ 5, 6, 7 ], 4 ] }

obj.hasOwnProperty,返回值是一个布尔值,即是否是obj的属性(原型上的是false)

  1. 深拷贝:遍历,如果是简单数据类型直接赋值,如果是复杂数据类型递归。
// 深拷贝
let obj1 = {
    name : '春娇',
    arr : [1,[2,3],4],
};
let obj4=deepClone(obj1)
obj4.name = "志明";
obj4.arr[1] = [5,6,7] ; // 新对象跟原对象不共享内存
// 这是个深拷贝的方法
function deepClone(obj) {
    if (obj === null) return obj; 
    if (obj instanceof Date) return new Date(obj);
    if (obj instanceof RegExp) return new RegExp(obj);
    if (typeof obj !== "object") return obj;
    let cloneObj = new obj.constructor();
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        // 实现一个递归拷贝
        cloneObj[key] = deepClone(obj[key]);
      }
    }
    return cloneObj;
}
console.log('obj1',obj1) // obj1 { name: '春娇', arr: [ 1, [ 2, 3 ], 4 ] }
console.log('obj4',obj4) // obj4 { name: '志明', arr: [ 1, [ 5, 6, 7 ], 4 ] }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值