实现深浅拷贝的几种方式

247 阅读2分钟

这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战

三、实现深浅拷贝

前文已经介绍过实现深浅拷贝的各一个方式Object.assign({}, c)JSON.parse(JSON.stringify(c))(乞丐版),本文也将继续实践其他种类的深浅拷贝

3.1 浅拷贝

对于浅拷贝一般都是一行代码就行了,比较实现的目的比较单纯,只需要第一层为实体复制即可,主要分为两大阵营,一类是远古时期,一类是现代文明。

远古时期

其实现在也在用,没那么老😂,只是实现方式没那么现代,代码比较长。。。

3.1.1 Array.prototype.slice()Array.prototype.concat()

利用的是这两个方法返回新数组的特性进行浅拷贝数组(因为这两个方法是数组的方法😂)

let a = [[1,2],2,3,4]
let b = a.slice() // < 等-价 >   let b = a.concat()
b[0][0] = 10
b[1] = 20       

a、b的结果如下图,可以看出,和我前文提到的浅拷贝怪异的现象一致,第一层复制的是实体,第二层复制的是引用,所以b[1]改变时,a[1]未改变;b[0][0]改变时,a[0][0]也跟着改变,详情可看我前文详细理解深浅拷贝存在的意义!!!

image-20210817222056963.png

3.1.2 对象浅拷贝

没有找到相关比较老的方法实现,可以使用函数循环遍历实现

function cloneObj (traget) {
    let ret = {}
    for (let key in target) {
        ret[key] = target[key]
    }
    return ret
}

现代文明

主要以ES6中的两种方式可以实现,一个是Object.assign、一个是扩展运算符

3.1.3 Object.assign(target, ...sources)
let obj = {
  name: 'shengjingyin',
  cc: {
    name:"juliya"
  },
}
let newObj = Object.assign({},  obj)
​
obj.name = 'juliya'
obj.cc.name = 'juliya'

image-20210817223135728.png

3.1.4 ...扩展运算符

与上面唯一的不同就是=号运算时不同,结果完全一样,这才是现代化好吗,简洁舒适通用。

let newObj = { ...obj }
//--------对于数组也是一样的-------
let oldArr = [[1,2],2,3,4]
let newArr = [ ...oldArr ]

浅拷贝介绍了远古时期和现代文明的几种方式,要我选的话我会推荐后两种,特别是扩展运算符

3.2 深拷贝

深拷贝的实现的方式也有很多种(主要思想是递归)

3.2.1 JSON.parse(JSON.stringify( target ))

let a = [[1,2],2,3,4]
let b = JSON.parse(JSON.stringify(a))
a[0][0] = 5
a[1] = 20

结果如下,多层数据均为复制实体,前后无关联

image-20210817223945358.png

3.2.2 递归

简单版递归深拷贝,主要思路:判断值是否为对象,是对象的话需要进行递归调用,这个版本有很多种!!!

function cloneDeep1(source) {
    var target = {};
    for(var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
            if (typeof source[key] === 'object') {
                target[key] = cloneDeep1(source[key]); // 注意这里
            } else {
                target[key] = source[key];
            }
        }
    }
    return target;
}