JS 深克隆

229 阅读1分钟

利用JSON

var obj1 = {
    a: 1,
    b: '2',
    c: [1,2]
}
var obj2 = JSON.parse(JSON.stringify(obj1))

obj2.a = 3
console.log(obj1) // { a: 1, b: '2', c: [ 1, 2 ] }
console.log(obj2) // { a: 3, b: '2', c: [ 1, 2 ] }

JSON不能处理的数据类型:

  • Function、 undefined、Symbol会丢失
  • Date(转换后变成字符串)、RegExp和Error(转换后变成空对象{})
  • NaN、Infinity和-Infinity 转换后变成null
  • 只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;

Object.assign

var obj1 = {
    a: 1
}
var obj2 = {
    b: 2
}
Object.assign(obj1, obj2)
console.log(obj1) //{ a: 1, b: 2 }
console.log(obj2) // { b: 2 }

弊端:当多层嵌套的属性为对象时依旧只是拷贝了对象的引用,如下

var obj1 = {
    a: 1
}
var obj2 = {
    b: 2,
    c: {
        cc: 9
    }
}
Object.assign(obj1, obj2)
obj2.c.cc = 0
console.log(obj1) // { a: 1, b: 2, c: { cc: 0 } } obj1和obj2的c属性指向同一个对象

递归拷贝

JavaScript内置的引用类型:
Array、Date、Error、Function、Object、RegExp

以下只考虑了数组、原装Object的情况

function deepClone(val) {
    if(val.constructor == Object) {
        let obj = {}, keys = Object.keys(val)
        for(let i = 0; i < keys.length; i++) {
            obj[keys[i]] = deepClone(val[keys[i]])
        }
        return obj
    } else if (Array.isArray(val)) {
        return [].concat(val)
    } else {
        return val
    }
}
var obj1 = {
    a: 2,
    b: {
        bb: 22
    }
}
var obj2 = deepClone(obj1)
obj1.b.bb = 99
console.log(obj1)  // { a: 2, b: { bb: 99 } }
console.log(obj2)  // { a: 2, b: { bb: 22 } }