深拷贝的几个误区

  周末赋闲在家,由于太冷了,不想出门,索性宅一天好了。可是闲着没事作老是很无聊的,正好新的一年想抓一下童鞋同窗的代码质量,就随便打开了几个童鞋写的代码。因而故事就展开了。javascript

  团队大了以后,如何统一团队代码风格实际上是一个蛮重要的问题,目前咱们团队使用lint的方式进行了限制,此次的review能够说是初见成效,除了很多同窗偷偷摸摸的经过noverify的方式提交代码之外。不过没看多久就发现了一段有趣的代码:java

 

function deepClone(obj, res = {}) {
    const _res = res;
    for(let key in obj) {
        if (obj[key] == obj) {
            continue;
        }

        if (typeof obj[key] === 'object') {
            if(Array.isArray(obj[key])){
                _res[key] = obj[key].slice();
            } else {
                _res[key] = deepClone(obj[key], _res[key]);
            }
        } else {
            _res[key] = obj[key];
        }
    }
    return _res;
}

 

  初看上去就会好奇,为何不使用lodash现成的深拷贝呢?一看是个h5的项目,推测多是为了总体包的大小作了取舍,也无可厚非吧。不过仔细看代码,乍一看好像还挺好,还细心的考虑的数组的状况,可是再仔细看得时候又以为好像有什么地方不对,若是入参是个字符串感情你给别人返回一个空对象么。。跑了一个case发现果真有点问题:node

 

var c = { a:1 };
var d = new Map();
d.set('a', 1);
var a = {
    a: 1,
    b: true,
    c: ()=>{console.log(123)},
    d: [1,2],
    e: d,
    f: c,    
    g: {} 
}
var b = deepClone(a);

  

  一、虽然正常的处理好像都没有什么问题,可是遇到新的数据结构如Map的时候,这种拷贝就会出问题;数组

  二、另外,它只处理了单层循环引用的状况,多层的时候状况会更复杂;安全

  三、并且这样递归,层级一深还会有爆栈的隐患,至关的不安全...网络

  四、虽然它对单独处理的数组的拷贝,但若是数组的某项的值是一个对象,它这样的处理依然有问题...数据结构

  因此深拷贝究竟应该怎么写呢?google

  本着能google不手写的原则,查了下网络,好的写法没发现几个,却是几个误区经有的文章常常会提到且一笔略过:对象

 

  一、JSON.parse(JSON.stringify(obj)) 的实现究竟算不算深拷贝?blog

    固然算,可是这种实现有几个潜在风险:

      1)它的原理是将可以JSON化的值JSON化,再从新生成一个新的JSON对象。因此它可以实现的基础是这个值是可以被JSON化的,像诸如function、map、set全是不能JSON化的,一转就没了。

      2) 它还有一个风险是在处理循环引用时是会报错的。这点不少童鞋在实操的时候特别容易忽略,特别是在node端进行端端通讯的时候,曾经一个报错查半天,真的是血的教训。

    因此,若是是纯JSON的数据的深拷贝且不包含循环引用,是可使用这个方法的

 

  二、递归在js中是有风险的

     常见的实现都是基于递归的,可是递归自己在js的runtime,很容易由于层级过深而致使爆栈。

     而一般的方式则是经过“拍平”树级结构的对象成一个数组,来进行拷贝。

  

  三、深拷贝的状况因业务场景的定义会有不一样  

    有些业务场景须要保持拷贝对象中的值的引用关系不变,而有些却要改变。另外,js的数据结构发展到今天,须要在拷贝时处理的边界状况已经不少了,你须要好好考虑清楚哪些状况须要怎么处理。

  

  其实话说回来,仔细看得话,你会发现第一种写法和jQuery中extend的方式实际上是很像的,一般的状况也基本能覆盖了,不过在如今这个语境下,相比比较“安全”的实现深拷贝,仍是建议使用lodash的cloneDeep(相比jQuery和underscore深拷贝大概60行左右的代码,lodash使用了近几百行代码,考虑了各类边界状况,也可谓是业界楷模了)

相关文章
相关标签/搜索