javascript 对象深拷贝

原生js的对象拷贝都是浅拷贝,如果需要深拷贝则要手动做一些操作

使用json序列化和反序列化

例子:

let obj = {         
  name: 'lizitao',
  msg: {
    age: '2'
  }
}; 
let cp = JSON.parse(JSON.stringify(obj));
console.log(cp);

优点: 写起来非常简单
缺点:局限性太多了。因为只支持json所支持的那些数据类型。像函数、undefined、正则等这些都是不支持的。遇到环状结构则会报错:

var obj = {
     a: undefined
 };
 console.log(JSON.parse(JSON.stringify(obj)))  // {}
 // 属性a被自动忽略了

JSON.stringify则会检测是否存在环,存在则抛出错误

var obj = {};
obj.child = obj;
JSON.stringify(a)  // Uncaught TypeError: Converting circular structure to JSON

所以我们只能复杂一点的方式,用递归来实现深拷贝

第一版(雏形),能复制简单对象
const clone = function(source){
    if(source instanceof Object){
        let result = {}
        for (const key in source) {
            result[key] = clone(source[key])
        }
        return result
    } else {
        return source
    }
}

先判断是否为对象,非对象则直接返回它的值。如果是对象则新建一个空对象 {},并复制属性到该对象上。注意属性的复制是递归调用clone函数的:result[key] = clone(source[key]),这样才能保证每一层都是深拷贝!。
不过它只判断了是否为对象,并假设对象都是像{name: value}的形式。如果对象是数组、函数、日期等等就不能正常运行了。所以要判断对象到底是哪种类型的对象,并根据对象具体类型来初始化result,用这样的形式:

if(source instanceof Object){
    //...
    if(source instanceof Array){
       //... 
    } else if(source instanceof Function){
       //...
    } else if(source instanceof Date){
       //...
    }
    // 省略许多else if, 判断越详细那么支持的对象类型就越多
    else {
       //...
    }
} else {
    //...
}

于是我们按照这个思路写出第二版

第二版,支持多种类型的对象
const clone = function(source){
    if(source instanceof Object){
        let result = null
        if(source instanceof Array){
            result = []
        } else if(source instanceof Function){
            result = function(){
                return source.apply(this, arguments)
            }
        } else if (source instanceof Date) {
            result = new Date(source);
        } else {
            result = {}
        }
        for (const key in source) {
            result[key] = this.clone(source[key])
        }
        return result
    } else {
        return source
    }
}

最后要解决的是对象是环的情况。基本思路是用一个数组来存储所有复制过的对象,每次调用前先判断对象是否复制过了,如果复制过就直接返回。

你可能感兴趣的:(javascript)