总结一下js中常用的对象、数组拷贝方式。

js中的数据分为基本数据类型和引用数据类型,基本数据类型是直接访问变量对应的值,而引用数据类型是通过读取变量引用地址获取到值。

深浅拷贝是相对于引用类型来说的。

浅拷贝指的是直接将引用类型的引用(对象在内存中的地址)复制给另一个变量,这样改变引用类型的值就都会改变。

深拷贝指的是在内存中新开辟一块内存来存放拷贝的引用类型,也就是指向一个新的内存地址,这样改变引用类型的值不会对另外一个引用类型的值产生影响。

# 浅拷贝

# Object.assign()

const source = { name: 'susan', age: 18, family: { father: 'jenny'} }
const target = Object.assign({}, source)
target.name = '小花'
console.log(source.name) // 小花
console.log(target.name) // 小花

const newTarget = Object.assign({}, source)
newTarget.family.father = 'bob' // 注意 虽然多层的引用类型还是浅拷贝
newTarget.name = 'Lily'
console.log(source.name, source.family.father) // 小花 bob
console.log(newTarget.name, newTarget.family.father) // Lily bob

# concat()

let source = [110, { name: 'susan' }]
let target = source.concat()
target[1].name = '小花'
console.log(source[1].name) //小花 

# slice()

const source = [1, { name: 'susan' }]
const target = source.slice()
target[1].name = '小花'
console.log(source) // [1, { name: '小花' }]
console.log(target) // [1, { name: '小花' }]

# 扩展运算符

扩展运算符只是深拷贝了第一层,对深层的引用拷贝还是属于浅拷贝

const source = { name: 'susan', age: 18, family: { father: 'jenny'} }
const target = { ...source }
source.name = '小花'
source.family.father = 'bob'
console.log(source) // 小花
console.log(target) // susan

const sourceArr = [1,2,3, { name: 'susan'} ]
const targetArr = [...sourceArr]
targetArr.push(4)
targetArr[3].name = 'Lily'
console.log(sourceArr) // [1,2,3, { name: 'Lily' }]
console.log(targetArr) // [1,2,3, { name: 'Lily' }, 4]

# 深拷贝

# JSON.parse(JSON.stringify())

对正则、函数、date等无法正确地拷贝

const source = [1, { name: 'susan'}]
const target = JSON.parse(JSON.stringify(source))

# 递归遍历

// 判断类型
function getType(target) {
    return Object.prototype.toString.call(target).slice(8, -1)
}

// 递归遍历拷贝
function copy(target) {
    let result, targetType = getType(target)
    if(targetType === 'Object') {
        result = {}
    } else if(targetType === 'Array') {
        result = []
    } else {
        return target
    }
    // 遍历
    for(let i in target) {
        let val = target[i]
        if(getType(val) === 'Object' || getType(val) === 'Array') {
            result[i] = copy(val)
        } else {
            result[i] = val
        }
    }
    return result
}