JS中深拷贝数组、对象、对象数组方法

我们在JS程序中需要进行频繁的变量赋值运算,对于字符串、布尔值等可直接使用赋值运算符 “=” 即可,但是对于数组、对象、对象数组的拷贝,我们需要理解更多的内容。

首先,我们需要了解JS的浅拷贝与深拷贝的区别。

我们先给出一个数组:

var arr = ["a","b"];

现在怎么创建一份arr数组的拷贝呢?直接执行赋值运算吗?我们来看看输出结果

var arrCopy = arr;
arrCopy[1] = "c";
arr   // => ["a","c"]

可以发现对拷贝数组 arrCopy 进行操作时原数组也相应地被改变了,这就是JS的浅拷贝模式。所以我们可以指出对数组、对象、对象数组进行简单赋值运算只是创建了一份原内容的引用,指向的仍然是同一块内存区域,修改时会对应修改原内容,而有时候我们并不需要这种模式,这就需要对内容进行深拷贝。

1 数组的深拷贝



对于数组的深拷贝常规的有三种方法:

方法一:遍历复制

1 var arr = ["a", "b"], arrCopy = [];
2 for (var item in arr) arrCopy[item] = arr[item];
3 arrCopy[1] = "c";
4 arr   // => ["a", "b"]
5 arrCopy   // => ["a", "c"]

考虑伪多维数组可以写成函数形式:

function arrDeepCopy(source){
    var sourceCopy = [];
    for (var item in source) sourceCopy[item] = typeof source[item] === ‘object‘ ? arrDeepCopy(source[item]) : source[item];
    return sourceCopy;
}

这种方法简单粗暴,但是利用JS本身的函数我们可以更加便捷地实现这个操作。

方法二:slice()

可以参考 W3School 对 slice() 方法的描述:slice() 方法可从已有的数组中返回选定的元素。

调用格式为:

arrayObject.slice(start,end)

方法返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。该方法并不会修改数组,而是返回一个子数组。

在这里我们的思路是直接从数组开头截到尾:

arrCopy = arr.slice(0);
arrCopy[1] = "c";
arr   // => ["a", "b"]
arrCopy   // => ["a", "c"]

可以看出成功创建了一份原数组的拷贝。

方法三:concat()

可以参考 W3School 对 concat() 方法的描述:concat() 方法用于连接两个或多个数组。

调用格式为:

arrayObject.concat(arrayX,arrayX,......,arrayX)

该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。

使用这种方法的思路是我们用原数组去拼接一个空内容,放回的便是这个数组的拷贝:

arrCopy = arr.concat();
arrCopy[1] = "c";
arr   // => ["a", "b"]
arrCopy   // => ["a", "c"]

2、对象的深拷贝



对于数组的深拷贝我们有了概念,那么一般对象呢?

我们给出一个对象:

var obj = { "a": 1, "b": 2 };

同样做测试:

var objCopy = obj;
objCopy.b = 3;
obj   // => { "a": 1, "b": 3 }
objCopy   // => { "a": 1, "b": 3 }

同样,简单的赋值运算只是创建了一份浅拷贝。

而对于对象的深拷贝,没有内置方法可以使用,我们可以自己命名一个函数进行这一操作:

var objDeepCopy = function(source){
    var sourceCopy = {};
    for (var item in source) sourceCopy[item] = source[item];
    return sourceCopy;
}

但是对于复杂结构的对象我们发现这个函数并不适用,例如:

var obj = { "a": { "a1": ["a11", "a12"], "a2": 1 }, "b": 2 };

所以需要进行一点修改:

var objDeepCopy = function(source){
    var sourceCopy = {};
    for (var item in source) sourceCopy[item] = typeof source[item] === ‘object‘ ? objDeepCopy(source[item]) : source[item];
    return sourceCopy;
}
var objCopy = objDeepCopy(obj);
objCopy.a.a1[1] = "a13";
obj   // => { "a": { "a1": ["a11", "a12"], "a2": 1 }, "b": 2 }
objCopy   // => { "a": { "a1": ["a11", "a13"], "a2": 1 }, "b": 2 }

3、对象数组的深拷贝



如果再考虑更奇葩更复杂的情况,例如我们定义:

var obj = [{ "a": { "a1": ["a11", "a12"], "a2": 1 }, "b": 2 }, ["c", { "d": 4, "e": 5 }]];

这是一个由对象、数组杂合成的奇葩数组,虽然我们平时写程序基本不可能这么折腾自己,但是可以作为一种特殊情况来考虑,这样我们就可以结合之前说的方法去拓展拷贝函数:

var objDeepCopy = function (source) {
    var sourceCopy = source instanceof Array ? [] : {};
    for (var item in source) {
        sourceCopy[item] = typeof source[item] === ‘object‘ ? objDeepCopy(source[item]) : source[item];
    }
    return sourceCopy;
}
var objCopy = objDeepCopy(obj);
objCopy[0].a.a1[1] = "a13";
objCopy[1][1].e = "6";
obj   // => [{ "a": { "a1": ["a11", "a12"], "a2": 1 }, "b": 2 }, ["c", { "d": 4, "e": 5 }]]
objCopy   // => [{ "a": { "a1": ["a11", "a13"], "a2": 1 }, "b": 2 }, ["c", { "d": 4, "e": 6 }]]

这样它就可以作为一个通用函数替我们进行深拷贝操作了。

原文地址:https://www.cnblogs.com/xfcao/p/9955170.html

时间: 2024-10-08 10:49:01

JS中深拷贝数组、对象、对象数组方法的相关文章

JS 中深拷贝的几种实现方法

JS 中深拷贝的几种实现方法1.使用递归的方式实现深拷贝 //使用递归的方式实现数组.对象的深拷贝 function deepClone1(obj) { //判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝 var objClone = Array.isArray(obj) ? [] : {}; //进行深拷贝的不能为空,并且是对象或者是 if (obj && typeof obj === "object") { for (key i

JS中的内置对象简介与简单的属性方法

JS中的数组: 1.数组的概念: 数组是在内存中连续存储的多个有序元素的结构,元素的顺序称为下标,通过下标查找对应元素 2.数组的声明: ①通过字面量声明var arr1 = [,,,,] JS中同一数组可以储存多种不同的数据类型(但,同一数组一般只用于存放同种数据类型) 例如var arr1 = [1,"2",true,{"name":"啦啦啦"},[1,2]]; ②通过new关键字声明:var arr2 = new Array(参数); &g

JS中深拷贝与浅拷贝的区别,实现深拷贝的几种方法

JS中深拷贝与浅拷贝的区别,实现深拷贝的几种方法 如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力. 此篇文章中也会简单阐述到栈堆,基本数据类型与引用数据类型,因为这些概念能更好的让你理解深拷贝与浅拷贝. 我们来举个浅拷贝例子: let a=[0,1,2,3,4], b=a; console.log(a===b); a[0]=1; console.log(a,b); 嗯?明明b复

JavaScript -- 时光流逝(六):js中的正则表达式 -- RegExp 对象

JavaScript -- 知识点回顾篇(六):js中的正则表达式 -- RegExp 对象 1. js正则表达式匹配字符之含义 .     查找单个字符,除了换行和行结束符.\w    查找单词字符.\W     查找非单词字符.\d     查找数字.\D     查找非数字字符.\s     查找空白字符.\S     查找非空白字符.\b     匹配单词边界.\B     匹配非单词边界.\0     查找 NULL 字符.\n     查找换行符.\f     查找换页符.\r   

Js中常用的字符串,数组,函数扩展

由于最近辞职在家,自己的时间相对多一点.所以就根据prototytpeJS的API,结合自己正在看的司徒大神的<javascript框架设计>,整理了下Js中常用一些字符串,数组,函数扩展,一来可以练练手,二来也锻炼下自己的代码能力.由于代码里面的注释自认为已经非常详细,所以就直接贴代码了. 1. 字符串扩展: ;(function() { var method, stringExtends = { /** * 删除字符串开始和结尾的空白 * @returns {string} */ stri

php中向前台js中传送一个二维数组

在php中向前台js中传送一个二维数组,并在前台js接收获取其中值的全过程方法: (1),方法说明:现在后台将数组发送到前台 echo json_encode($result); 然后再在js页面中的ajax一部传送的返货函数中接收,最重要的是接受的时候设置一下接收参数的类型: $.post(              "http:"+$('#url').val()+"/search",              {drug_name:drug_name},    

js中test,exec和match方法

js中test,exec和match方法 转载▼ 标签: 杂谈 分类: jsp test test 返回 Boolean,查找对应的字符串中是否存在模式. var str = "1a1b1c";var reg = new RegExp("1.", "");alert(reg.test(str)); // true exec exec 查找并返回当前的匹配结果,并以数组的形式返回. var str = "1a1b1c";var

js中的子类继承父类的方法和属性

上次讲了个简单的继承,这次 咱们讲个稍微复杂点的,那就是让子类继承父类的属性和方法,假设人 (Person)是父类,工人(Worker)是子类,让worker继承person的属性和方法: 父类: function Person(name,age) { this.name=name; this.age=age; } Person.prototype.showName=function() { alert(this.name); } function worker(name,age,job) {

js中style.display=&quot;&quot;无效的解决方法

本文实例讲述了js中style.display=""无效的解决方法.分享给大家供大家参考.具体解决方法如下: 一.问题描述: 在js中我们有时想动态的控制一个div显示或隐藏或更多的操作,但如果我们style.display=""可能导致没有效果. 看下面一段代码: 复制代码代码如下: <style> #name {     display:none; }</style></head><body><div id=

JS中的call()方法和apply()方法用法总结

JS中的call()方法和apply()方法用法总结  : 参考   :     https://blog.csdn.net/ganyingxie123456/article/details/70855586 原文地址:https://www.cnblogs.com/wfblog/p/9169026.html