js数组和对象深拷贝

JavaScript4年前 (2020)更新 小马大哥哥
804 5 0

在JS中,一般的 = 号传递的都是对象/数组的引用,并没有真正地拷贝一个对象,那如何进行对象的深度拷贝呢?

对象的深拷贝

通常情况下,我们可以使用最简单,最直接的方法,JSON.parse()与JSON.stringfy()实现对象的深克隆,代码如下:

const clone = function(obj) {
    return JSON.parse(JSON.stringfy(obj));
}

但需要注意和记住的是,这种方法只适合纯数据JSON对象的深度克隆,不过也都可以满足我们日常情况下的开发,对于复杂结构的深拷贝,大家可以参考一下方法:

const clone = function (obj) { 
    if(obj === null) return null 
    if(typeof obj !== 'object') return obj;
    if(obj.constructor===Date) return new Date(obj); 
    if(obj.constructor === RegExp) return new RegExp(obj);
    var newObj = new obj.constructor ();  //保持继承链
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {   //不遍历其原型链上的属性
            var val = obj[key];
            newObj[key] = typeof val === 'object' ? arguments.callee(val) : val; // 使用arguments.callee解除与函数名的耦合
        }
    }  
    return newObj;  
};

补充方法 ES6扩展运算符实现对象的深拷贝

let aa={a:1,b:undefined,c:function(){},d:new Date()}

aa //{a: 1, b: undefined, c: ƒ, d: Tue Apr 23 2019 13:22:56 GMT+0800 (中国标准时间)}a: 1b: undefinedc: ƒ ()d: Tue Apr 23 2019 13:22:56 GMT+0800 (中国标准时间) {}__proto__: Object
let bb={...aa}

bb //{a: 1, b: undefined, c: ƒ, d: Tue Apr 23 2019 13:22:56 GMT+0800 (中国标准时间)}a: 1b: undefinedc: ƒ ()d: Tue Apr 23 2019 13:22:56 GMT+0800 (中国标准时间) {}__proto__: Object
aa.e=null
aa //{a: 1, b: undefined, c: ƒ, d: Tue Apr 23 2019 13:22:56 GMT+0800 (中国标准时间), e: null}
bb //{a: 1, b: undefined, c: ƒ, d: Tue Apr 23 2019 13:22:56 GMT+0800 (中国标准时间)}

数组深拷贝

数组的深拷贝,方法有很多

1、遍历

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

多重数组则写成方法,递归自己即可。

2、slice()

定义和用法
slice() 方法可从已有的数组中返回选定的元素。

语法
arrayObject.slice(start,end)

参数 描述
start 必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。

end 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。

返回值
返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。

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

3、concat()

定义和用法
concat() 方法用于连接两个或多个数组。

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

语法
arrayObject.concat(arrayX,arrayX,......,arrayX)

参数 描述
arrayX 必需。该参数可以是具体的值,也可以是数组对象。可以是任意多个。

返回值
返回一个新的数组。该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的。如果要进行 concat() 操作的参数是数组,那么添加的是数组中的元素,而不是数组。

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

4、JSON.parse()与 JSON.stringify()

(1)JSON.parse函数
作用:将json字符串转换成json对象。
语法:JSON. parse(text[,reviver]).
参数:text 必须;一个有效的json字符串。
reviver 可选。
返回值:一个对象或数组。

(2)JSON.stringify()函数
作用:将json对象转换成json字符串。
语法:JSON.stringify(value [, replacer] [, space])
参数:value 必须;通常为对象或数组。
replacer 可选,用于转换结果的函数或者数组。
space 可选。向返回值 JSON 文本添加缩进、空格和换行符以使其更易于读取。
返回值:一个包含JSON文本的字符串。

let arrCopy = JSON.parse(JSON.stringify(arr));
arrCopy[1] = "c";
arr   // => ["a", "b"] 
arrCopy   // => ["a", "c"]

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

… 扩展运算符是ES6的语法,使用起来非常的方便简洁,相信在写ES6的时候也是备受欢迎的。

let arrCopy = [...arr];
arrCopy[1] = "c";
arr   // => ["a", "b"] 
arrCopy   // => ["a", "c"]

© 版权声明

相关文章

5 条评论

您必须登录才能参与评论!
立即登录