精华内容
下载资源
问答
  • javascript中数组深拷贝途径及对象数组深拷贝 什么是浅拷贝 在js当中,我们常常遇到数组复制的的情况,许多人一般都会使用“=”来直接把一个数组赋值给一个变量,如: var a=[1,2,3]; var b=a; console.log(b); ...
  • 写前端的时候经常会遇到对象的拷贝,一般我们...总结一下常用的对象深拷贝以及数组对象深拷贝。1. 序列化转成json字符串深拷贝,以及存在的问题; 2. Object.assign()深拷贝,以及存在的问题; 3. 循环递归深拷贝

    写前端的时候经常会遇到对象的拷贝,一般我们会用到深拷贝,深拷贝就是完完整整的将一个对象从内存中拷贝一份出来,放到另一块新开辟的内存中去。向下面这种赋值是浅拷贝,a、b都是对同一块内存进行引用,a、b哪一个变量修改对象的属性值都会相互影响。总结一下常用的对象深拷贝以及数组对象的深拷贝。

    var a = {id:"",name:""}
    var b = a;
    
    1. 序列化转成json字符串深拷贝,以及存在的问题
    2. Object.assign()深拷贝,以及存在的问题
    3. 循环递归深拷贝

    一、序列化转成json字符串深拷贝

    例:

    let source = {"id":1};
    //序列化转成json字符串
    let jsonStr = JSON.stringify(source)
    //反序列化为对象
    let target = JSON.parse(jsonStr);
    

    存在的问题:
    此方法仅在原对象包含可序列化值类型且没有任何循环引用时才有效。不可序列化值类型的一个例子是 Date 对象 - JSON.parse 只能将其解析为字符串而无法解析回其原始的 Date 对象

    注:
    同时总结java的序列化
    序列化:就是把一个java对象转成字节流
    反序列化:就是把字节流转成java对象
    当然序列化不仅仅可以是转成字节流或者json字符串,还有很多种方式
    为什么在java对象要序列化,什么场景要序列化?
    如果没有序列化,怎么把一个在内存里面的对象保存到文件里面去,怎么把内存的对象通过网络传输到另一台计算机的内存去呢?序列化就是把内存的对象转成字节流或者json字符串等方式进行传输用的,用在一些保存对象到文件、网络传输对象等io流传输对象的场景。


    二、Object.assign()深拷贝

    Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
    基本语法:Object.assign(target, …sources)
    例:

    var source = {"id":1,name:"lin"};
    var target = Object.assign({},source);
    

    这样就可以把source对象里面的相同属性值拷贝到target对象

    存在的问题:
    如果要拷贝的对象source里面的属性不是基础类型也是对象,或者属性含有对象数组,这种方式的拷贝就不会把source对象里面的对象或者数组对象进行深拷贝
    例:

    var source = {"id":1,list:[{"name":"小明"},{"name":"小花"}]};
    var target = Object.assign({},source);
    

    这时target里面的属性list数组对象只是浅拷贝source里面的list,还是对同一块内存的引用
    也可以向下面这样优化,循环list数组里面的对象进行Object.assign拷贝,添加到一个新的数组去,然后再赋值给target.list
    例:

    let source = {"id":1,list:[{"name":"小明"},{"name":"小花"}]};
    let target = Object.assign({},source);
    //对象数组的深拷贝
    let newlist = [];
    for(let i=0;i<target.list.length;i++){
          let obj = Object.assign({}, target.list[i]);
          newlist.push(obj);
    }
    target.list = newlist;
    

    注:如果对象里面还含有对象属性,而里面的对象属性又含有对象属性,则这种方式很麻烦不合适。

    三、循环递归深拷贝

    function deepClone(obj, newObj) {
        var newObj = newObj || {};
        for (let key in obj) {
            if (typeof obj[key] == 'object') {
                let isArray = Array.isArray(obj[key]);//判断是否数组
                newObj[key] = (isArray == true ? [] : {})
                deepClone(obj[key], newObj[key]);
            } else {
                newObj[key] = obj[key]
            }
        }
        return newObj;
    }
    
    

    参考:
    网友haogemr的js 深度拷贝的几种方法

    展开全文
  • 对象数组深拷贝与浅拷贝,简单点来说,就是b复制了a,当a被修改时,未操作b,但b也跟着变了,就是浅拷贝,反之是深拷贝 深拷贝本身只针对较为复杂的object类型数据 浅拷贝 var a=[{name:'zhangsan',age:12},{name:'...

    对象数组的深拷贝与浅拷贝,简单点来说,就是b复制了a,当a被修改时,未操作b,但b也跟着变了,就是浅拷贝,反之是深拷贝

    深拷贝本身只针对较为复杂的object类型数据

    浅拷贝

    var a=[{name:'zhangsan',age:12},{name:'lisi',age:20}];
    var b=a;
    a[1].age=18;
    console.log(a,b);
    

    运行结果,a,b的age都发生了改变
    在这里插入图片描述
    伪深拷贝,仍然是浅拷贝 slice
    只对数组第一层有效

    var a=[{name:'zhangsan',age:12},{name:'lisi',age:20},1];
    var b=a.slice();
    a[1].age=18;
    a[2]=2
    console.log(a,b);
    

    在这里插入图片描述
    有缺陷的深拷贝
    它的主要缺点是,只限于处理可被 JSON.stringify() 编码的值。
    JSON.stringify() 将编码 JSON 支持的值。包含 Boolean,Number,String,以及对象,数组。其他任何内容都将被特殊处理。
    FunctionSymbol 时,它被忽略掉
    InfinityundefinedNaN 会被变成 null
    Date 对象会被转化为 String (默认调用date.toISOString())

    var a=[{name:'zhangsan',age:12},{name:'lisi',age:20},1,undefined,NaN];
    var b = JSON.parse(JSON.stringify(a))
    a[1].age=18;
    a[2]=2
    console.log(a,b);
    

    在这里插入图片描述
    深拷贝

    var a=[{name:'zhangsan',age:12},{name:'lisi',age:20}];
    var b=a.map(o => ({...o}));
    a[1].age=18;
    a[2]=2
    console.log(a,b);
    

    在这里插入图片描述
    JQuery方法深拷贝

    $.extend([deep],target,object1[,objectN])
    

    deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝

    targetObject类型 目标对象,其他对象的成员属性将被附加到该对象上。

    object1 objectN可选。 Object类型 第一个以及第N个被合并的对象

    b=$.extend(true,[],a);
    
    展开全文
  • javascript 数组以及对象深拷贝(复制数组或复制对象)的方法前言在js中,数组对象的复制如果使用=号来进行复制,那只是浅拷贝。如下图演示: 如上,arr的修改,会影响arr2的值,这显然在绝大多数情况下,并...

    javascript 数组以及对象的深拷贝(复制数组或复制对象)的方法

    前言

    在js中,数组和对象的复制如果使用=号来进行复制,那只是浅拷贝。如下图演示:

    如上,arr的修改,会影响arr2的值,这显然在绝大多数情况下,并不是我们所需要的结果。
    因此,数组以及对象的深拷贝就是javascript的一个基本功了。

    评论中有很多人说我误导大家。说这些都是浅拷贝。我不做过深的阐述,本文中涉及到的都是比较浅显的内容。诸位请根据自己的需要以及情况自行判断和理解。

    数组的深拷贝

    条条大道通罗马,实现数组的深拷贝,是有好几种方法的。举例如下:

    for 循环实现数组的深拷贝

    for循环是非常好用的。如果不知道高级方法,通过for循环能够完成我们大多数的需求。

    var arr = [1,2,3,4,5]
    var arr2 = copyArr(arr)
    function copyArr(arr) {
    	let res = []
    	for (let i = 0; i < arr.length; i++) {
    	 res.push(arr[i])
    	}
    	return res
    }
    

    如上,通过对数组的for循环,即可实现对数组的深拷贝了。

    slice 方法实现数组的深拷贝

    这个代码实现非常简单。原理也比较好理解,他是将原数组中抽离部分出来形成一个新数组。我们只要设置为抽离全部,即可完成数组的深拷贝。代码如下:

    var arr = [1,2,3,4,5]
    var arr2 = arr.slice(0)
    arr[2] = 5
    console.log(arr)
    console.log(arr2)
    

    运行结果如下:

    更多 slice 内容请访问 w3school JavaScript slice 方法

    concat 方法实现数组的深拷贝

    这个代码也非常简单,原理更加粗暴。它是用于连接多个数组组成一个新的数组的方法。那么,我们只要连接它自己,即可完成数组的深拷贝。代码如下:

    var arr = [1,2,3,4,5]
    var arr2 = arr.concat()
    arr[2] = 5
    console.log(arr)
    console.log(arr2)
    

    运行结果如下:

    更多 concat 内容请访问 w3school JavaScript concat 方法

    2017年10月31日补充:ES6扩展运算符实现数组的深拷贝

    OK,以上之前讲的方法全部过时了,用下面的方法实现数组的深拷贝是最简单的。

    var arr = [1,2,3,4,5]
    var [ ...arr2 ] = arr
    arr[2] = 5
    console.log(arr)
    console.log(arr2)
    

    运行结果如下:

    ES6扩展运算符实现数组的深拷贝

    对象的深拷贝

    对象的深拷贝相比数组也没有困难许多,列举两个方法。

    万能的for循环实现对象的深拷贝

    在很多时候,for循环能够解决大问题。

    var obj = {
      name: 'FungLeo',
      sex: 'man',
      old: '18'
    }
    var obj2 = copyObj(obj)
    function copyObj(obj) {
      let res = {}
      for (var key in obj) {
        res[key] = obj[key]
      }
      return res
    }
    

    转换成json再转换成对象实现对象的深拷贝

    上面的代码实在是比较长,所以,用一个更暴力的方法吧!代码如下:

    var obj = {
      name: 'FungLeo',
      sex: 'man',
      old: '18'
    }
    var obj2 = JSON.parse(JSON.stringify(obj))
    

    这个原理没什么好解释的,实在是够简单粗暴的啦!

    2017年10月31日补充: 扩展运算符实现对象的深拷贝

    var obj = {
      name: 'FungLeo',
      sex: 'man',
      old: '18'
    }
    var { ...obj2 } = obj
    obj.old = '22'
    console.log(obj)
    console.log(obj2)
    

    运行结果如下:

    扩展运算符实现对象的深拷贝

    小结

    数组和对象的深拷贝是js中最常见的应用。理解各种方法是必须的。希望对大家有所帮助。
    本文中并没有对异常进行处理,主要在讲原理。更多的数组以及对象的操作方法,可以参考lodash的源码,查看它的源码可以让你的js基础变得非常牢固。我也在学习中。

    2017年10月31日补充,使用es6提供的扩展运算符的方法实现深拷贝,简单,高效。并且,对象的深拷贝不会像使用 JSON 方法深拷贝一样,丢失函数等信息,只能用来深拷贝 JSON 数据格式的对象。推荐大家使用。

    补充一个数组去重的方法

    function dedupe(array) {
      return [...new Set(array)]
    }
    var arr = [1,2,2,3,3,4,4,5,5]
    console.log(dedupe(arr))
    

    运行结果如下:

    JS数组去重的方法

    2021年03月29日 补充

    这里说的深拷贝,都是指一维的数组和对象的深拷贝。鉴于评论中多人指出,这些是浅拷贝,我本来不想回应,但是提出这个观点的人很多,因此我在这边回应一下。

    浅拷贝的概念不重复了,上文中已经说明。文章中的多种方法,均不是浅拷贝,只是是否支持多维数据而已。而在绝大多数场景下,文中的方法是适用的。

    想要简便的支持多维数据的深拷贝,可以直接适用 JSON 方式。或适用 lodash 工具实现。

    版权申明:本文由FungLeo原创,允许转载,但转载必须附注首发链接。谢谢。

    展开全文
  • js对象数组深拷贝 前言 在javascript 以及 其他的很多编程语言中,对象与数组的赋值往往是引用类型的赋值,若a和b是两个对象,则赋值语句a=b,仅仅是把a “指向” 了 b,而不是把a原本的对象变为了b对象。这种赋值...

    js对象数组的深拷贝

    前言

    在javascript 以及 其他的很多编程语言中,对象与数组的赋值往往是引用类型的赋值,若a和b是两个对象,则赋值语句a=b,仅仅是把a “指向” 了 b,而不是把a原本的对象变为了b对象。这种赋值得到的结果可以称为 浅拷贝。

    但很多时候我们需要 深拷贝 。 需要复制一个一摸一样的对象 或者 数组, 来完成某些工作。

    这篇文章主要介绍了javascript中的深拷贝。

    本文实验直接在浏览器的console中进行。

    开始

    step.1 实现浅拷贝

    首先我们定义几个对象,来试一下对象赋值的结果是什么:

    let a={name:1,age:1};
    let b={name:2,age:2};
    a=b;
    a;
    b;
    

    此时,输入 a,按回车后,可以得到a的值为 {name:2,age:2}; 输入 b,按回车后,可以得到b的值为 {name:2,age:2}

    让我们继续

    a.name=3;
    b;
    

    我们对a的属性name进行了赋值,然后输入b按回车,得到了b的值为 {name: 3, age: 2}

    这就是问题的所在了。可以看出这仅仅是浅拷贝,仅仅改变了a的引用。a与b指向的是同一个对象,改变a时,也相当于改变了b

    step.2 实现深拷贝

    在step.1的基础上,我们想实现深拷贝,如何做呢

    首先我们将a与b的值初始化

    a={name:1,age:1};
    b={name:2,age:2};
    

    然后想让a变为b的深拷贝

    a={name:b.name,age:b.age};
    a.name=3;
    a;
    b;
    

    此时再看a与b的值,发现a的name为3,b的name为2; 我们成功的实现了深拷贝。

    step.3 数组/对象数组的深拷贝

    有了step2的经验,对于 数组 以及 对象数组 如何实现深拷贝呢 ? 方法也是类似的

    对于值类型的数组,

    a=[1,2,3];
    b=[4,5,6];
    a=b;
    a[0]=10;
    a;
    b;
    

    上面的操作是浅拷贝, 仅仅是把a指向了b指向的数组,所以a,b的值都是[10,5,6]

    下面的操作可以实现深拷贝

    a=[1,2,3];
    b=[4,5,6];
    a=[...b];
    a[0]=10;
    a;
    b;
    

    其中 a=[…b] ,相当于a=[b[0],b[1],b[2]],即把b拆分后重组成数组。

    对于对象数组来说,不仅要进行数组类似的深拷贝操作,还需要对每个对象进行对象的深拷贝操作。总结一句就是相当繁琐。

    step.4 通用深拷贝方法

    若对象中不包含方法等,仅仅包含了属性,则使用JSON序列化反序列化,可能是最简单粗暴的方法了;

    a=JSON.parse(JSON.stringify(b))
    

    先将b序列化为字符串,然后再转化为JSON对象,再赋值给a

    展开全文
  • 数组深拷贝 1、最简单的方法:使用ES6扩展运算符 var arr = [1,2,3,4,5] var copy = […arr] 测试: var arr = [1,2,3,4,5] var copy = [...arr] arr[2] = 5 console.log(arr) console.log(copy) 2、js数组concat/...
  • js实现数组深拷贝

    2020-08-10 16:59:23
    // 单层数组深拷贝 concat || ... //多层数组深拷贝 deepCopy(obj){ //只拷贝对象 if(typeofobj!=="object")return; //根据obj的类型判断是新建一个数组还是一个对象 letnewObj=objinstanceofArray?[]:{}; ...
  • 其实很简单,一般的数组去重可以直接用 new Set() 方法即可,但是数组对象的话,比较复杂,不能直接用,我们可以采取间接的方法来去重 unique(arr) { const res = new Map(); return arr.filter((arr) => !...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,926
精华内容 8,770
关键字:

js对象数组深拷贝