深拷贝

前言

这个话题在面试上已经是老生常谈了,今天让我们一起来学习下深拷贝。

定义

在引出定义前,我们先来看下面的例子:

var arr = [{
    name: 'foo'
}, {
    age: 20
}]
var newArr = arr.concat()

newArr[0].name = 'bar'
newArr[1].age = 24

console.log(arr) // [{name: "bar"}, {age: 24}]
console.log(newArr) // [{name: "bar"}, {age: 24}]

分析:首先 concat() 方法拷贝了 arr 对象到 newArr,但是我们改变 newArr 数组对象的值时,arr 的数组对象也会随着变化。为了不影响原数组对象的值,我们就需要使用深拷贝。

因此,深拷贝指的是创建一个新的对象和数组,将原对象的各项属性的「值」(数组的所有元素)拷贝过来,是「值」而不是「引用」。

实现

在拷贝的时候判断一下属性值的类型,如果是对象,我们就递归调用深拷贝函数。见下方:

function cloneDeep (val) {
    if (typeof val === 'object') {
        var newVal = val instanceof Array ? [] : {}
        for (var key in val) {
            if (val.hasOwnProperty(key)) {
                newVal[key] = typeof val[key] === 'object' ? cloneDeep(val[key]) : val[key]
            }
        }
        return newVal
    }
}

var arr = [{
    name: 'foo'
}, {
    age: 20
}]
var newArr = cloneDeep(arr)

newArr[0].name = 'bar'
newArr[1].age = 24

console.log(arr) // [{name: "foo"}, {age: 20}]
console.log(newArr) // [{name: "bar"}, {age: 24}]

性能问题

尽管使用深拷贝会完全的克隆一个新对象,不会产生副作用,但是深拷贝因为使用递归,性能会不如浅拷贝,在开发中,还是要根据实际情况进行选择。

结语

本文到这里就结束了。通过这篇文章了解深拷贝的定义和实现,以及它的性能问题。希望本文能够帮助到你,共勉!

参考文献

JavaScript专题之深浅拷贝在新窗口打开