js深度拷贝和浅度拷贝的深入理解

2023-05-16

首先我们来说说什么是拷贝:就是复制的同时加上了传值。

然后问题就来了什么是有深度的什么是浅度的,在想要了解我们这个问题之前我们先来了解一下下面的一个知识点

基本类型传递,引用类型传递

首先我们来看下基本类型传递:就是基本数据类型之间的数据传递,什么是基本数据类型呢?string,number,boolean,null,undefined

他们这些类型的值发生传递的时候是将自己复制了一份,吧赋值的哪一份传递给了莫一个变量;

引用类型传递:就是引用类型的值的的一个传递,那么什么是引用类型呢?就是对象(object,Arrey,RegExp,function),他们都是对象,对象之间的赋值就不会吧自己复制一份,为什么呢?你想想假设每一个对象都是一个很大的房间,我们要把所有房间里的东西都复制一份,和房间里面的小物品都要按原来的方式摆好来是不是太耗费时间了,所以在对象之间的传输,只是赋值了钥匙(指针),就是我们都有了这个房间的钥匙,所以就会出现大家可能知道的引用类型之间的传递的时候其中一个改变,另一个也会发生改变

当你们看懂了上面的之后我们就来分析一下上面是深度的什么是浅度的

浅拷贝是拷贝一层,深层次的对象级别的就拷贝引用;深拷贝是拷贝多层,每一级别的数据都会拷贝出来;‘/

下面我们就来些一些方法来看下如何实现深度拷贝?

那么如何实现呢?可能大家一时间想不起来?那就对了,那就看下下面的这个例子

var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c };
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- b 沒被改到
console.log(obj2);
// { a: 10, b: 100, c: 30 }

有人看了就奇怪了为什么这样就没关系了呢?为什么?想一想?

对没错就是这样:因为obj1.a 这个值它是一个基本类型,当我们在一次改变这个obj1.a这些基本类型值的时候是改变的他们的复制的副本,所以就没关系了?对不对啊?

没错?其实还是有一定问题?什么问题呢?如果我们ibj1.a他还是一个对象,那么他就还是一个引用类型那么我们不就还是不可以吗对把?嗯是的还是不可以?

那么我们需要干上面呢?就是要把对象改为基本类型;

    var obj = {}
    var a = {
      b: 10,
      c: {
        d: 11,
        e: 13,
      },
    }

这个例子中:如是可以的obj.b = a.b,但是obj.c = a.c 这个是不可以的因为a.c还是一个对象,那么现在obj.c还是一个钥匙,他改变了值,原来的a对象还是会改变,所以a.c这个对象还要在分变成obj.c.d = a.c.d 这样就可以了,那么怎么分呢?用递归

 

 // arguments.callee 当前函数
    function deepClone(initaObj, finalObj) {
      var obj = finalObj || {};
      for (var i in initaObj) {
        if (typeof initaObj[i] === 'object') {
          obj[i] = (initaObj[i].constructor === Array) ? [] : {};
          arguments.callee(initaObj[i], obj[i]);
        } else {
          obj[i] = initaObj[i];
        }

      }
      return obj;
    }

arguments.callee():表示调用的函数本身,为什么用这个不用deepClone()这个呢?减少耦合性,当要改变函数名的时候,就可以少改一次

这样就可以达到把对象中的属性值中的对象在分一遍?

但是有没有想过代码中的一些问题

1.obj[i] = (initaObj[i].constructor === Array) ? [] : {}; 这一行代码的作用是什么

我来告诉大家因为有可能属性值是一个数组同时也可能是数组,为了确保拷贝是一样就这样了

2.输出的值是什么

    var obj = {};
    var a = {
      a: 1,
      b: {
        c: 11,
        d: 111,
      },
      e: [2, 3, 4, 5]
    }
    console.log(deepClone(a, obj));

假设加上什么的代码执行会输出和和a对象一样的值,看上去对了,我们的目的就是要复制一个和他一样的值,但是他们虽然他们值是一样的但是可以确保他们不是同一个房子,而是我们需要的两个房子呢?我们只需要改变obj中的属性值看下a中的会不会也随着发生改变就可以了,答案是不会的( 测试下),所以是对了

{a: 1, b: {…}, e: Array(4)}
a: 2
b: {c: 11, d: 111}
e: (4) [2, 3, 4, 5]
__proto__: Object

obj.a = 2
a.a = 1

其实也就是每下项都是一基本类型的值传给新的对象,但是是一层一层的传,同时要注意是不是数组,(其实还有其他的但是目前不考虑,比如函数)

3.下一个问题就是还有一个情况就是遇到了属性值是函数function怎么办?答案是可以的

为什么呢?我把我的理解写一下:函数的这个房间,和数组和对象的区别是函数这个房间他是不可以改变,他会自己运行完了自己毁灭,防止内存泄漏(占了太多没用的内存,整体的内存泄漏了)

首先 typeof function !== object 而是等于 Function 运行上面的函数obj[i] = initaObj[i];那么新的对象你某一个属性他也会变成了一个(钥匙)指针,这个函数的房间是没办法去改变的,你去改变只是换了给钥匙,或者说是变成了基本类型的值,原来需要给你复制的对象的某一个属性,它还是拿的打开那个房间的钥匙(还是那个函数的指针,指向那个函数,随时运行) ,所以是可以的

4.当旧值,等于新值怎么办?(在迭代中要思考的问题)那么用这个就会无限循环,所以我们可以加这一行代码

几乎不会出现的情况

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i];        // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
    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 obj1 = { fun: function(){ console.log(123) } };
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(typeof obj1.fun);
// 'function'
console.log(typeof obj2.fun);
// 'undefined' <-- 没复制

但是这个方法有2点不好

1.就是要用json的格式,属性值不可以用function 但是可以把他赋值去了

2.譬如它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。

第三种

继承的方法(如果不了解继承可以跳过)

    function deepClone(initalObj, finalObj) {
      var obj = finalObj || {};
      for (var i in initalObj) {
        var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
        if (prop === obj) {
          continue;
        }
        if (typeof prop === 'object') {
          obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
          if (obj[i].constructor === Array) {
            console.log('数组');
            arguments.callee(prop, obj[i]);
          }
        } else {
          obj[i] = prop;
        }
      }
      return obj;
    }

Object.create(prop);的作用是什么?

Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 ---MDN

所以作用就继承了上一层的值,也达到了效果obj[i]继承了prop的属性值,当他去改变的时候,只是新增加他自己的属性值,而

他继承的属性,的属性值他是改变不了的,所以也是带到了效果

第4种

用jquery 和 lodash 的函数框架

好了这个内容就到这里了 如果文中有什么错误,可以来和我说一下,嘿嘿

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

js深度拷贝和浅度拷贝的深入理解 的相关文章

  • 如何用border来画三角形

    学习总结 HTML lt div class 61 34 son 34 gt lt div gt CSS son width 0px border 20px solid border color black transparent tran
  • window和document的区别

    window对象 它是一个顶层对象 而不是另一个对象的属性 xff0c 即浏览器的窗口 document 当前显示的文档 该属性本身也是一个对象
  • JS距离的理解

    偏移量 offsetWidth 元素在水平方向上占用的空间大 xff0c 包括元素的宽度 可见的垂直滚动条宽度 左边框高度和右边框高度 offsetWidth 61 width 43 padding 43 border offsetHeig
  • 汉堡按钮的制作以及其中的问题

    第一种自己写的 xff0c 下面的第二种是网上的用一个span使用做出来的 HTML lt div class 61 34 box 34 gt lt chang用来判断是否变换 gt lt span class 61 34 s1 34 gt
  • 对js动画和时间控制的使用

    JavaScript Document 打算移动的元素ID xff1b elementID 该元素的目的地的 34 左 34 位置 xff1b final x 该元素的目的地的 34 上 34 位置 xff1b final y 停顿时间 x
  • css动画小结

    一 转换 transform IE9 43 1 旋转rotate transform rotate 30deg ms transform rotate 30deg IE 9 webkit transform rotate 30deg Saf
  • Django 判断访问来源是PC端还是手机端

    pc or mobile py 判断访问来源是pc端还是手机端 import re def judge pc or mobile ua 34 34 34 param ua 访问来源头信息中的User Agent字段内容 return 34
  • 圆形进度条是学习

    学习网站 xff1a http www cnblogs com jr1993 p 4677921 html CSS margin 0px padding 0px box margin 50px auto 0 width 300px heig
  • 定位插件

    写了个等位插件 xff0c 点击nav中的LI xff0c 位移 xff08 与href有视觉效果 xff09 到达相应板块 xff08 这里的类比li中的类中多了个H字母 xff09 的位置 lt li class 61 34 wz 34
  • JQ复习

    一选择器 1 基本选择器 2 层级选择器 3 过滤选择器 first 选取第一个元素 last 选择最后一个元素 not 去除所有与给定选择器匹配的元素 39 input not first 39 even选取索引是偶数的元素 xff0c
  • 第7章艺术编程Ajax的学习

    终于学到Ajax以前一直没接触到一直以为很NB xff0c 对这些内容我基本上是个小白中的小白哎 xff0c 继续加油 Ajax可以做到只更新页面的一下部分 xff0c 其他部分不需要重新加载 下面就是根据书上的内容所写 HTML lt d
  • 函数是否加括号的问题

    lt a onclick 61 34 fun 34 gt lt a gt 这里有括号 document getElementById 34 ID 34 onclick 61 fun 这里不可以有括号 为什么会有这样的不同 首先加上括号是执行
  • this的详细分析加案例

    this对象是在函数运行时候基于函数的执行环境 xff08 上下文 xff09 绑定的 方法调用模式函数调用模式改造器调用模式apply call bind调用模式 1 方法调用模式 函数有所属对象 xff0c 也就是这个函数是myObje
  • 构造函数与原型链和面向对象的学习(一)

    什么是构造函数 构造函数就是一个普通的函数 xff0c 里面可以写任何语句 逻辑语句或DOM操作 xff0c 可以new出新的实例 xff0c 使其实例可以共享构造函数的原型 第一个例子 function Fun this name 61
  • 构造函数与原型链和面向对象的学习(二)

    原型链 proto proto 也就是对象的 prototype 属性 每一个函数都有一个属性叫做prototype 指向一个对象 不是函数就没有这个属性 这个对象叫原型对象 当这个构造函数被new的时候 xff0c 他的每一个实例对象的
  • 构造函数与原型链和面向对象的学习(三)

    小案例 xff08 红绿灯 xff09 下面对面向对象写个小案例 xff08 红绿灯 xff09 上面是原图 用来来实现点击图片 xff0c 红绿灯的颜色改变 xff0c 控制背景图片的定位来改变 点击一下 就是要完成上面的效果 如果只要实
  • js中的预编译和作用域链

    预编译目的 1 定义作用域中的初始化词法环境 xff0c 而词法环境中有定于作用域 xff0c 从而规定了变量的作用域 2 先是在为undefined xff0c 减少运行时报错 形参去实参的区别 1 形参变量只有在被调用时才分配内存单元
  • ffmpeg视频处理神器学习基础笔记

    FFmpeg文档汇总 xff1a https ffmpeg org documentation html FFmpeg filters文档 xff1a https ffmpeg org ffmpeg filters html 视频处理 视频
  • Vue.js动画和过渡

    vue中的过渡与动画 过滤 把需要添加动画效果的DIV放到transition标签 之后就会发生以下3个步骤 自动嗅探目标元素是否应用了 CSS 过渡或动画 xff0c 如果是 xff0c 在恰当的时机添加 删除 CSS 类名 等下要写的6

随机推荐

  • Vue.js使用keyframes动画

    lt DOCTYPE html gt lt html gt lt head gt lt meta charset 61 34 utf 8 34 gt lt title gt Vue中css动画的原理 lt title gt lt scrip
  • Vue.js使用animate.css框架

    1 如何使用animate框架 lt DOCTYPE html gt lt html gt lt head gt lt meta charset 61 34 utf 8 34 gt lt title gt Vue中css动画的原理 lt t
  • vue.js中添加动画

    通过触发事件 xff0c 改变data中的值 xff0c 或者改变点击标签元素上的属性值 lt DOCTYPE html gt lt html lang 61 34 en 34 gt lt head gt lt meta charset 6
  • 多个元素和列表的过渡

    多个元素 lt DOCTYPE html gt lt html lang 61 34 en 34 gt lt head gt lt meta charset 61 34 UTF 8 34 gt lt title gt 多个元素的组件的过渡动
  • flex弹性布局的学习

    布局的传统解决方案是基于盒状模型 xff0c 依赖 display 43 position 43 float 方式来实现 xff0c 灵活性较差 2009年 xff0c W3C提出了一种新的方案 Flex xff0c Flex是Flexib
  • 震惊!Ajax项目中的使用

    啊啊 xff01 实习第一天写了个移动端的分享列表 就在第三天我们的技术大佬亲自教我们如何对接后台 当然用的是我写的移动端的分享列表 虽然这次应用不是很深入 xff0c 但还是比较广泛 用到了Ajax xff0c sui框架 zepto x
  • 关于viewport视口的学习

    简单来说 lt meta name 61 34 viewport 34 content 61 34 width 61 device width initial scale 61 1 0 34 gt content属性值 width 可视区域
  • 淘宝的H5布局

    利用viewport和rem布局实现的淘宝布局 下面先看看em布局的原理 em作为font size的单位时 xff0c 其代表父元素的字体大小 xff0c em作为其他属性单位时 xff0c 代表自身字体大小 MDN em作为字体单位 x
  • css的优先级

    优先级 浏览器通过优先级来判断哪些属性值与一个元素最为相关 xff0c 从而在该元素上应用这些属性值 优先级是基于不同种类选择器组成的匹配规则 优先级是如何计算的 优先级就是分配给指定的 CSS 声明的一个权重 xff0c 它由 匹配的选择
  • Django设置分享到微信好友和朋友圈时的标题、摘要、链接和图片

    主要参考官方文档 1 前端分享给好友和朋友圈的js代码 share html lt DOCTYPE html gt lt html lang en gt lt head gt lt meta charset UTF 8 gt lt meta
  • 孙其功陪你学之——如何将shell命令的返回值赋值给应用程序的变量

    如何将shell命令的返回值赋值给应用程序的变量 博主最近做了个路由器的项目 xff0c 需要得到路由器现在网络状态和参数 xff0c 使用UCI get 获得 xff0c 但是使用了system xff08 UCI get xff09 之
  • shell编程2条件语句

    文章目录 shell编程之条件语句1 条件测试1 1 返回值1 2 test 2 文件测试3 整数值比较4 逻辑测试5 if语句5 1 单分支 if 语句5 2 双分支 if 语句5 3 多分支 if 语句 6 case 语句7 实验7 1
  • html和css的hack的学习

    在整理基础的时候总结 html和css的hack的学习 hack是什么 xff1f 就是针对不同的浏览器写不同的css样式让各浏览器能达到一致的渲染效果 xff0c hack分为HTML和CSS HTML hack lt if lte IE
  • 数组的迭代与归并的方法

    迭代的作用 xff1a 减少代码量 xff1a 例如因为map xff0c filter方法会自动生产数组不用自己在for创建 xff0c 有利于性能优化 xff1b 和无需知道对象的长度 补充19 6 11 xff1a 迭代的方法是表达式
  • js数组的常见属性和方法

    属性 strong length strong 是Array的实例属性 返回或设置一个数组中的元素个数 该值是一个无符号 32 bit 整数 xff0c 并且总是大于数组最高项的下标 xff0c 不只是可读 Array prototype
  • js闭包的作用和应用的学习

    什么是闭包 一个函数和对其周围状态 xff08 lexical environment xff0c 词法环境 xff09 的引用捆绑在一起 xff08 或者说函数被引用包围 xff09 xff0c 这样的组合就是闭包 xff08 closu
  • css面试题布局

    不试试怎么知道自己行不行 昨天加了张鑫旭的微信 xff0c 我草贼开心 xff0c 发现他星期六会直播 xff0c 一下就是我看直播学到的一些总结 那么是什么呢 xff1f 其实就是一个简单的左右排版 xff0c 在张老师的讲了4种不是很好
  • 获取css的方法区别

    不试试怎么知道自己不可以 xff1f 对吧 首先我们要知道css在HTML中有多少总方法 xff1f 呵呵大家都知道的 行内 xff1a 顾名思义就是和标签在同一行 lt div class 61 34 text 34 style 61 3
  • 关于offsetLeft和offsetTop的兼容性问题

    不试一下怎么知道自己不可以 xff1f 首先我们要看下offsetLeft和offsetTop他们两的API的作用 xff1b 元素相对于offsetParent的左边距和上边距 xff08 为什么没有bottom xff0c right呢
  • js深度拷贝和浅度拷贝的深入理解

    首先我们来说说什么是拷贝 xff1a 就是复制的同时加上了传值 然后问题就来了什么是有深度的什么是浅度的 xff0c 在想要了解我们这个问题之前我们先来了解一下下面的一个知识点 基本类型传递 xff0c 引用类型传递 首先我们来看下基本类型