JavaScript的浅拷贝和深拷贝
发布日期:2021-05-04 17:17:13 浏览次数:35 分类:精选文章

本文共 5019 字,大约阅读时间需要 16 分钟。

JavaScript中的浅拷贝与深拷贝

前言

在学习JavaScript时,理解数据类型的基础知识是必不可少的。JavaScript中的数据类型分为基本数据类型和引用类型。基本数据类型如numberstringboolean等是按值访问的,且值是不可变的;而引用类型如objectarray等是按引用访问的,且值是动态可变的。

数据类型的比较特点

  • 值比较:基本数据类型的比较是按值进行的。
  • 引用地址比较:引用类型的比较是按引用地址进行的。
  • 基于以上特点,我们可以初步想到,所谓的浅拷贝深拷贝可能分别对应于值的拷贝和引用的拷贝。基本数据类型的拷贝不需要区分,因为它们都是按值拷贝的。对于引用类型的拷贝,我们需要明确其是浅拷贝还是深拷贝。

    浅拷贝

    浅拷贝是指只复制对象的一层属性,而不深入处理其内部的引用类型。浅拷贝的过程中,对象的引用会被拷贝,但其内部的对象、数组等引用类型仍然指向原对象的内存地址。

    数组的浅拷贝

    要实现数组的浅拷贝,有多种方法可以选择:

  • slice方法
  • var zxxArr = ["One", "Two", "Three"];
    var zxxArrs = zxxArr.slice(0);
    zxxArrs[1] = "love";
    console.log(zxxArr); // ["One", "Two", "Three"]
    console.log(zxxArrs); // ["One", "love", "Three"]
    1. concat方法
    2. var zxxArr = ["One", "Two", "Three"];
      var zxxArrs = zxxArr.concat();
      zxxArrs[1] = "love";
      console.log(zxxArr); // ["One", "Two", "Three"]
      console.log(zxxArrs); // ["One", "love", "Three"]
      1. 扩散运算符(ES6)
      2. var zxxArr = ["One", "Two", "Three"];
        var zxxArrs = [...zxxArr];
        zxxArrs[1] = "love";
        console.log(zxxArr); // ["One", "Two", "Three"]
        console.log(zxxArrs); // ["One", "love", "Three"]

        对象的浅拷贝

        对象的浅拷贝同样可以通过多种方法实现:

      3. 手动循环拷贝
      4. function simpleCopy(obj1) {
        var obj2 = Array.isArray(obj1) ? [] : {};
        for (let i in obj1) {
        if (obj1.hasOwnProperty(i)) {
        obj2[i] = obj1[i];
        }
        }
        return obj2;
        }
        var zxxObj = {
        age: 18,
        nature: ['smart', 'good'],
        names: {
        name1: 'zxx',
        name2: 'xka'
        },
        love: function () {
        console.log('zxx is a great girl');
        }
        };
        var newZxxObj = simpleCopy(zxxObj);
        newZxxObj.age = 8;
        newZxxObj.nature.push('why');
        newZxxObj.names.name1 = 'why zxx';
        newZxxObj.love = function () {
        console.log('zxx is 18 years old');
        };
        console.log(zxxObj.age); // 18
        console.log(zxxObj.nature); // ["smart", "good", "why"]
        console.log(zxxObj.names); // {name1: "why zxx", name2: "xka"}
        console.log(zxxObj.love); // ƒ () {console.log('zxx is a great girl')}
        1. Object.assign方法
        2. var zxxObj = {
          age: 18,
          nature: ['smart', 'good'],
          names: {
          name1: 'zxx',
          name2: 'xka'
          },
          love: function () {
          console.log('zxx is a great girl');
          }
          };
          var newZxxObj = Object.assign({}, zxxObj);
          newZxxObj.age = 8;
          newZxxObj.nature.push('why');
          newZxxObj.names.name1 = 'why zxx';
          newZxxObj.love = function () {
          console.log('zxx is 18 years old');
          };
          console.log(zxxObj.age); // 18
          console.log(zxxObj.nature); // ["smart", "good", "why"]
          console.log(zxxObj.names); // {name1: "why zxx", name2: "xka"}
          console.log(zxxObj.love); // ƒ () {console.log('zxx is a great girl')}
          1. ES6对象扩展语法
          2. var zxxObj = {
            age: 18,
            nature: ['smart', 'good'],
            names: {
            name1: 'zxx',
            name2: 'xka'
            },
            love: function () {
            console.log('zxx is a great girl');
            }
            };
            var newZxxObj = {...zxxObj};
            newZxxObj.age = 8;
            newZxxObj.nature.push('why');
            newZxxObj.names.name1 = 'why zxx';
            newZxxObj.love = function () {
            console.log('zxx is 18 years old');
            };
            console.log(zxxObj.age); // 18
            console.log(zxxObj.nature); // ["smart", "good", "why"]
            console.log(zxxObj.names); // {name1: "why zxx", name2: "xka"}
            console.log(zxxObj.love); // ƒ () {console.log('zxx is a great girl')}

            深拷贝

            深拷贝是对对象及其所有子对象进行逐层拷贝,确保新对象与原对象完全独立,不互相影响。

            深拷贝的实现方法

          3. JSON.stringifyJSON.parse
          4. var zxxObj = {
            age: 18,
            nature: ['smart', 'good'],
            names: {
            name1: 'zxx',
            name2: 'xka'
            },
            love: function () {
            console.log('zxx is a great girl');
            }
            };
            var newZxxObj = JSON.parse(JSON.stringify(zxxObj));
            newZxxObj.age = 8;
            newZxxObj.nature.push('why');
            newZxxObj.names.name1 = 'why zxx';
            newZxxObj.love = function () {
            console.log('zxx is 18 years old');
            };
            console.log(zxxObj.age); // 18
            console.log(zxxObj.nature); // ["smart", "good"]
            console.log(zxxObj.names); // {name1: "zxx", name2: "xka"}
            console.log(zxxObj.love); // ƒ () {console.log('zxx is a great girl')}
            console.log(newZxxObj); // {age: 8, nature: Array(2), names: Object, love: Function}
            1. 循环递归拷贝
            2. function deepClone(initalObj, finalObj) {
              var obj = finalObj || {};
              for (var i in initalObj) {
              var prop = initalObj[i];
              if (prop === obj) {
              continue;
              }
              if (typeof prop === 'object') {
              obj[i] = (prop.constructor === Array) ? [] : {};
              arguments.callee(prop, obj[i]);
              } else {
              obj[i] = prop;
              }
              }
              return obj;
              }
              var zxxObj = {
              age: 18,
              nature: ['smart', 'good'],
              names: {
              name1: 'zxx',
              name2: 'xka'
              },
              love: function () {
              console.log('zxx is a great girl');
              }
              };
              var newZxxObj = deepClone(zxxObj);
              newZxxObj.age = 8;
              newZxxObj.names.name1 = 'newzxx';
              console.log(zxxObj);
              console.log(newZxxObj);
              1. jQuery或Zepto的.extend方法
              2. var $ = require('jquery');
                var newObj = $.extend(true, {}, obj);

                深拷贝的注意事项

              3. 性能问题:对于大型复杂对象,使用JSON.stringify可能会导致性能问题。
              4. 循环引用:如果对象中存在循环引用,如const a = {val: 2}; a.target = a;,深拷贝会导致系统栈溢出。
              5. 函数和原型成员:深拷贝过程中,对象的函数和原型成员会被丢失。
              6. 总结

                在实际应用中,根据需求选择合适的拷贝方法非常重要。浅拷贝适用于不需要深入拷贝子对象的场景,而深拷贝则适用于需要确保对象独立性的情况。无论是哪种拷贝方式,都需仔细分析对象的结构,确保拷贝过程中的准确性和完整性。

    上一篇:webpack面试题大全(持续更新)
    下一篇:详解javascript的堆栈原理,引用类型与基本类型区别(不考虑闭包的情况下)

    发表评论

    最新留言

    不错!
    [***.144.177.141]2025年05月08日 22时51分23秒

    关于作者

        喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
    -- 愿君每日到此一游!

    推荐文章

    Nmap端口服务 之 CentOS7 关于启动Apache(httpd)服务、telnet服务、smtp服务、ftp服务、sftp服务、snmp服务 2025-03-28
    PHP系列:PHP 基础编程 2(时间函数、数组---实现登录&注册&修改) 2025-03-28
    PHP系列:使用PHP实现登录注册功能的完整指南 2025-03-28
    Python&aconda系列:cmd/powershell/anaconda prompt提示“系统找不到指定的路径”(亲测有效) 2025-03-28
    Python&aconda系列:(W&L)Conda使用faiss-gpu报错及解决办法、安装numpy的坑、cmd执行Python脚本找不到第三方库、安装tensorflow-gpu时遇到的from 2025-03-28
    python&anconda 系列:Pycharm在debug问题的N种解决方案(一般程序、web方向、人工智能方向) 2025-03-28
    python&anconda系列(亲测有效):tensorflow AttributeError: ‘str’ object has no attribute ‘decode’ 2025-03-28
    python&anconda系列:tf.keras.backend.get_session()和keras.backend.get_会话()返回不同的会话对象(待解答) 2025-03-28
    "WARNING: Increasing RAM size to 1GB" and "Cannot set up guest memory 'xxx.ram': Invalid argument". 2025-03-28
    #if 0 #elif 1 #else #endif 用法 2025-03-28
    (反射+内省机制的运用)简单模拟spring IoC容器的操作 2025-03-28
    (转)tomcat7.0 manager app和host manager web管理 2025-03-28
    .Net(C#)实现异步编程 2025-03-28
    .Net中webBrowser控件JS交互 2025-03-28
    .Net中webBrowser控件指定IE版本 2025-03-28
    02-Docker镜像分类及操作秘籍,轻松掌握导出、导入、删除 2025-03-28
    04-docker-commit构建自定义镜像 2025-03-28
    04-docker系列-commit构建自定义镜像 2025-03-28
    05-docker系列-使用dockerfile构建镜像 2025-03-28
    05-如何通过Dockerfile实现高效的应用容器化? 2025-03-28