• 详解js中的对象的深浅拷贝


    前言

    本文是整理的浅拷贝和深拷贝中涉及的知识点,在工作中是非常重要的,在面试中也是必考的,希望对小伙伴们有所帮助!

    cmd-markdown-logo

    为什么会产生深浅拷贝?

    首先我们要知道一个流程

    1,对象属于引用类型的,以后浏览器会为其开辟一个新的内存空间,并为它分配一个16进制的地址

    2,按照一定的顺序,把对象的键值对存储到内存空间

    3,把开辟的内存地址赋值给变量(或事件),以后变量就通过地址找到内存空间,然后进行操作

    基本数据类型和引用数据类型

    数据分为基本数据类型和引用数据类型

    基本数据类型

    StringNumberBooleanNullUndefinedSymbol
    复制代码

    基本数据类型是直接存储在栈中的数据

    let str1 = '123';
    str2 = str1;
    str2 = '456';
    console.log(str1); // '123'
    console.log(str2); // '456'
    复制代码

    形象举例:

    我之前买了一双鞋子,我现在又买了一双,某一双坏了不会影响到另外一双

    引用数据类型

    ArrayObject
    复制代码

    引用数据类型存储的是该对象在栈中引用,真实的数据存储在内存中

    let arr1 =[1,2,3,4,5,6];
    arr2 = arr1;
    arr2.pop();
    console.log(arr1);//[ 1, 2, 3, 4, 5 ]
    console.log(arr2);//[ 1, 2, 3, 4, 5 ]
    复制代码

    形象举例:

    在大草原上,有一些羊吃了腐烂的草得病死了。草原还是草原,但是内部的草变少了;羊群还是羊群,但是内部的羊变少了

    深拷贝和浅拷贝的概念

    浅拷贝:

    仅仅复制对象的引用,而不是对象本身
    复制代码

    深拷贝:

    把复制的对象所引用的全部对象都复制一遍
    复制代码

    深拷贝和浅拷贝的区别

    cmd-markdown-logo
    cmd-markdown-logo

    ~ 和原数据是否指向同一对象 第一层数据为基本数据类型 原数据中包含子对象
    赋值 改变会使数据一同改变 改变会使原数据一同改变
    浅拷贝 改变不会使原数据一同改变 改变会使数据一同改变
    深拷贝 改变不会使原数据一同改变 改变不会使原数据一同改变

    浅拷贝

    通用循环

    const arr1 = [1, 2, ['ming', 'abc'], 5];
    
    const shallowClone = (arr) => {
      const dst = [];
      for (let prop in arr) {
        if (arr.hasOwnProperty(prop)) {
            dst[prop] = arr[prop];
        }
      }
      return dst;
    }
    
    const arr2 = shallowClone(arr1);
    arr2[2].push('wuhan');
    arr2[3] = 5;
    
    console.log(arr1);
    console.log(arr2);
    复制代码

    运行结果:

    cmd-markdown-logo

    object.assign()

    • Object.assign()方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象
    • Object.assign()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身
        const obj1 = {
            username:'ming',
            skill:{
                play:['backetball','game'],
                rend: 'book',
            },
            girlfriends:['xiaomi','xiaohong','xiaolan'],
        };
        const obj2 = Object.assign({},obj1);
        obj2.username = 'memg';//修改基本类型
        obj2.skill.read = 'e-mail';//修改二层基本类型
        obj2.skill.play = ['footbool'];//修改二层引用类型
        obj2.girlfriend = ['xiaoming'];
        console.log(obj1);
        console.log(obj2);
    复制代码

    运行结果:

    cmd-markdown-logo

    Array.prototype.concat()

    concat()是数组的一个内置方法,用户合并两个或者多个数组

    这个方法不会改变现有数组,而是返回一个新数组

      const arr1 = [1,{username: 'ming',},];
      let arr2 = arr1.concat();
      arr1[0] = 2;
      arr1[1].username = 'meng';
      console.log(arr1);
      console.log(arr2);
    复制代码

    运行结果:

    cmd-markdown-logo

    Array.prototype.slice()

    slice()也是数组的一个内置方法,该方法会返回一个新的对象

    slice()不会改变原数组

    const arr1 = [1,{username:'ming',},];
    let arr2 = arr1.slice();
    arr2[0] = 2;
    arr2[1].username = 'meng'
    console.log(arr1);
    console.log(arr2); 
    复制代码

    运行结果:

    cmd-markdown-logo

    obj展开运算符

    展开运算符是ES6中新提出来的一种运算符

    在拷贝数组、对象以及拼接数组等方面都可以使用

    这步我们也可以尝试下使用const obj2 = {...obj1}的形式进行浅拷贝

    //拷贝数组
    const arr1 = [1, 2, 3];
    const arr2 = [...arr1]; // like arr.slice()
    arr2.push(8); 
    
    console.log(arr1); // [ 1, 2, 3 ]
    console.log(arr2); // [ 1, 2, 3, 8 ]
    
    //拷贝对象
    const obj1 = {
      name: 'ming',
      arr1: ['9', '7', '6'],
      obj: {
        name: 'meng',
        arr2: ['7', '8', '9'],
      },
    };
    const obj2 = {...obj1};// like arr.slice()
    obj2.name = 'ming2';
    obj2.arr1 = ['null'];
    obj2.obj.name = 'meng2';
    obj2.obj.arr2 = ['null'];
    
    console.log(obj1);
    console.log(obj2);
    复制代码

    运行结果:

    cmd-markdown-logo

    深拷贝

    手动递归

    function deepClone (sourceObj, targetObj) {
        let cloneObj = targetObj || {}
        if(!sourceObj || typeof sourceObj !== "object" || sourceObj.length === undefined){
            return sourceObj
        }
        if(sourceObj instanceof Array){
            cloneObj = sourceObj.concat()
        } else {
            for(let i in sourceObj){
                if (typeof sourceObj[i] === 'object') {
                    cloneObj[i] = deepClone(sourceObj[i], {})
                } else {
                    cloneObj[i] = sourceObj[i]
                }
            }
        }
        return cloneObj
    }
    let sourceObj = {
      a: 1,
      b: {
        a: 1
      },
      c: {
        a: 1,
        b: {
          a: 1
        }
      },
      d: function() {
        console.log('hello world')
      },
      e: [1, 2, 3]
    }
    let targetObj = deepClone(sourceObj, {})
    targetObj.c.b.a = 9
    console.log(sourceObj)
    console.log(targetObj)
    复制代码

    运行结果:

    cmd-markdown-logo

    Json.parse(Json.Stringify())

    JSON.stringify():把一个js对象序列化为一个JSON字符串

    JSON.parse():把JSON字符串反序列化为一个js对象

    const arr9 = [
        1,
        {
          username:'ming',
        },
      ];
      let arr10 = JSON.parse(JSON.stringify(arr9));
      arr10[0]=2;
      arr10[1].username='meng';
      console.log(arr9);
      console.log(arr10);
    复制代码

    运行结果:

    cmd-markdown-logo

    let obj = {
        name: 'ming',
        age: 20,
        friend: {
          name: 'ming1',
          age: 19
        }
      };
      let copyObj = JSON.parse(JSON.stringify(obj));
      obj.name = 'meng';
      obj.friend.name = 'meng1';
      console.log(obj);
      console.log(copyObj);
    复制代码

    运行结果:

    cmd-markdown-logo

    函数库Lodash

    Lodash作为JavaScript函数库/工具库,它里面有非常好用的封装好的功能

    var _= require('lodash');
    const obj1 = [
      1,
      'Hello!',
      { name:'ming1' },
      [
        {
          name:'meng1',
        }
      ],
    ]
    const obj2 = _.cloneDeep(obj1);
    obj2[0] = 2;
    obj2[1] = 'Hi!';
    obj2[2].name = 'ming2'
    obj2[3][0].name = 'meng2';
    console.log(obj1);
    console.log(obj2);
    复制代码

    运行结果:

    cmd-markdown-logo

    来源:https://juejin.cn/post/6844904004611211271#heading-3
  • 相关阅读:
    【hibernate】自定义转换器
    【hibernate】存储图片
    【hibernate】映射可嵌入式组件
    【hibernate】应用程序级别的视图
    adb shell模拟点击事件(input tap)
    Android UIAutomator 定位
    adb devices连接不上设备
    获取元素属性get_attribute
    wait_activity
    webview定位 & native和webview切换
  • 原文地址:https://www.cnblogs.com/konglxblog/p/16756233.html
Copyright © 2020-2023  润新知