JavaScript-深拷贝、浅拷贝

本文档适用于有一定经验的开发者。我们默认你已经掌握了指针的概念(也可称为地址) ,如果你是新手,你可能需要先了解 指针的概念

我们在JS中经常需要复制一个对象或数组。
当我们直接使用=赋值时,我们实际只赋值了这个对象的指针。这种情况 连拷贝都算不上
例:如下我们给array2赋值,实际是赋值给array2一个指针,指针指向array1指向的数组。因此我们编辑 array2 时,array1也会变。

let array1 = [1,2,3]
let array2 = array1
array2[0] = 100
/*
 array1
>(3) [100, 2, 3]
array2
(3) [100, 2, 3]
*/

浅拷贝可以将数组(对象)的第一层拷贝下来。
ES6给我们提供了两个方便的浅拷贝方法:
Array.from()Object.assign()
例:下面我们通过Array.from()对array3进行浅拷贝。我们可以看出,当我们修改array4的普通元素时,array3已经不会随着改变了。但是浅拷贝只是拷贝了第一层的元素,如果第一层元素含有对象(数组),我们只拷贝一个指针(地址)。array4通过这个指针(地址)访问的对象将是与array3是相同的。

let array3 = [1,2,3,{a:1,b:2,c:3}]
let array4 = Array.from(array3)
array4[0] = 100
array4[3].a = 100
/*
array3
>(4) [1, 2, 3, {a: 100, b: 2, c: 3}]
array4
>(4) [100, 2, 3, {a: 100, b: 2, c: 3}]
*/

目前JS常见的深拷贝有两种方式。第一种种是两次JSON化:
let array6 = JSON.parse(JSON.stringfiy(array5))
这种方法很简单,但是当元素含有undefined正则表达式时函数会抛出异常。
第二种深拷贝是逐层遍历逐一赋值的方法,要麻烦一些,但是没有第一种的缺点。
目前,这两种以外的拷贝方式都是浅拷贝。例如for...of遍历中的item实际是对对象元素的浅拷贝。

// 例:逐层遍历逐一赋值的深拷贝工具类
class deepCopy {
    static toRawType(value) {
        return Object.prototype.toString.call(value).slice(8, -1);
    }
    /* 已整合在tools中 */
    static copy(obj) {
        let emptyObject = null;
        if (this.toRawType(obj) == 'Object') {
            emptyObject = {};
        }
        else if (this.toRawType(obj) == 'Array') {
            emptyObject = [];
        }
        else {
            return obj;
        }
        for (let key in obj) {
            if (typeof obj[key] != 'object' || obj[key] == null) {
                emptyObject[key] = obj[key];
            }
            else {
                emptyObject[key] = this.copy(obj[key]);
            }
        }
        return emptyObject;
    }
}
let array5 = [1,2,3,{a:1,b:2,c:3}]
let array6  = deepCopy.copy(array5)
array6[3].a = 100
/*
array3
>(4) [1, 2, 3, {a: 1, b: 2, c: 3}]
array4
>(4) [1, 2, 3, {a: 100, b: 2, c: 3}]
*/
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。