zoukankan      html  css  js  c++  java
  • JS 数组、对象的深拷贝

    博客地址:https://ainyi.com/72

    JavaScript 程序中,对于简单的数字、字符串可以通过 = 赋值拷贝
    但是对于数组、对象、对象数组的拷贝,就有浅拷贝和深拷贝之分

    浅拷贝就是当改变了拷贝后的数据,原数据也会相应改变

    来说说深拷贝

    数组深拷贝

    遍历赋值

    不推荐此方法

    let a = [1, 2, 3]
    let b = []
    for (let val of a) {
      b.push(val)
    }
    b.push(4)
    a // [1, 2, 3]
    b // [1, 2, 3, 4]
    

    slice()

    数组方法 slice() 可从已有的数组中返回选定的元素
    那么设置为 0,就是返回整个数组

    let a = [1, 2, 3]
    let b = a.slice(0)
    b.push(4)
    a // [1, 2, 3]
    b // [1, 2, 3, 4]
    

    concat()

    数组方法 concat() 连接一个或多个数组,并返回一个副本
    那么不设置参数,就返回本数组

    let a = [1, 2, 3]
    let b = a.concat()
    b.push(4)
    a // [1, 2, 3]
    b // [1, 2, 3, 4]
    

    ES6 方法

    let a = [1, 2, 3]
    let b = [...a]
    b.push(4)
    a // [1, 2, 3]
    b // [1, 2, 3, 4]
    
    let a = [1, 2, 3]
    let b = Array.from(a)
    b.push(4)
    a // [1, 2, 3]
    b // [1, 2, 3, 4]
    

    对象深拷贝

    Object.assign()

    Object.assign(target, obj)

    let a = { name: 'krry' }
    let b = Object.assign({}, a)
    b.name = 'lily'
    a // { name: 'krry' }
    b // { name: 'lily' }
    

    注意使用 assign() 有如下特点:

    1. 不会拷贝对象继承的属性、不可枚举的属性、属性的数据属性/访问器属性
    2. 可以拷贝 Symbol 类型

    扩展运算符

    let a = { name: 'krry' }
    let b = { ...a }
    b.name = 'lily'
    a // { name: 'krry' }
    b // { name: 'lily' }
    


    以上是简单数组、对象的深拷贝方法,但是对于二维数组、对象数组、对象里包含对象,以上方法均达不到深拷贝方法
    以上只能达到数组、对象的第一层的深拷贝,对于里面的数组或对象属性则是浅拷贝,因为里面的内存地址只是拷贝了一份,但都是指向同一个地址
    所以当改变数组、对象里的数组元素或对象,原数据依然会改变

    二维数组、对象数组、多层对象的深拷贝

    最常用的 JSON 序列化与反序列化

    使用 JSON.parse(JSON.stringify(obj))

    let a = [1, [2, {aa: 2}, [4]], {aa: 5, cc: { dd: 6 }}]
    let b = JSON.parse(JSON.stringify(a)) // 完美
    

    通过 JSON.stringify 实现深拷贝有几点要注意
    1. 拷贝的对象的值中如果有函数、undefined、symbol,则经过 JSON.stringify() 序列化后的 JSON 字符串中这个键值对会消失
    2. 无法拷贝不可枚举的属性,无法拷贝对象的原型链
    3. 拷贝 Date 引用类型会变成字符串
    4. 拷贝 RegExp 引用类型会变成空对象
    5. 对象中含有 NaN、Infinity 和 -Infinity,则序列化的结果会变成 null
    6. 无法拷贝对象的循环应用(即 obj[key] = obj)

    自己实现深拷贝方法

    function deepCopy(obj) {
      let result = Array.isArray(obj) ? [] : {};
      for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
          if (typeof obj[key] === 'object') {
            result[key] = deepCopy(obj[key]);   // 递归复制
          } else {
            result[key] = obj[key];
          }
        }
      }
      return result;
    }
    

    lodash 的深拷贝 cloneDeep

    使用 lodash 插件的深拷贝方法

    // 官方例子
    var objects = [{ 'a': 1 }, { 'b': 2 }];
     
    var deep = _.cloneDeep(objects);
    console.log(deep[0] === objects[0]);
    // => false
    

    传送门:https://www.lodashjs.com/docs/4.17.5.html#cloneDeep

    博客地址:https://ainyi.com/72

  • 相关阅读:
    【Tools】xshell添加命令按钮Button
    【Optimization】ARM的寻址方式(详细)
    【Python】python文件或文本加密(4种方法)
    【Optimization】常用SSE Intrinsic指令总结
    【Optimization】X86汇编快速入门
    【Base】如何理解Latency和Throughput: 吞吐量和延迟
    【Cmd】Windows下批处理常用命令总结
    【Optimization】SSE指令集学习:Compiler Intrinsic
    【ASM】汇编指令movdqa与movdqu的区别
    anaconda
  • 原文地址:https://www.cnblogs.com/ainyi/p/10756070.html
Copyright © 2011-2022 走看看