美文网首页
原生JavaScript实现JSON合并(递归深度合并)

原生JavaScript实现JSON合并(递归深度合并)

作者: 黄努努 | 来源:发表于2017-03-13 20:51 被阅读0次

    为什么我会想到写这几行代码

    在实际工作中,我们会使用许多或自主开发或第三方的工具,有些工具的配置文件相当细节,使用频率低倒也罢了,使用频率高的话必然造成很多代码冗余。所以我都会对这些工具做二次封装,把不经常改动的配置给予默认值。如果需要改动,传入新的配置覆盖原来的配置即可。

    起初我以为这是一项很简单的需求

    var json1 = {    // 固定的配置
      a: 1,
      b: 2,
      c: 3,
    }
    
    var json2 = {    // 作为参数传入的配置
      a: 11,
      d: 14,
    }
    
    json3 = {    // 合并后的结果 
      a: 11,
      b: 2,
      c: 3,
      d: 14,
    }
    
    

    如上述,确实很简单。可事实是,当配置不再是仅仅一层嵌套时,常用的合并如$.extendfor in 赋值就不再能再解决问题了

    var json1 = {
      a: 1,
      b: {
        b1: 'hello',
        b2: 'world',
      },
    }
    
    var json2 = {
      b: { b2: 'china' },
      c: 3,
    }
    
    json3 = {    // 合并后的结果 
      a: 1,
      b: { b2: 'chila' },
      c: 3,
    }
    

    可以看出,我们的本意是希望json2里的b.b2: 'china'取代json1里的b.b2: 'world', 可是实际上,常规的结果只会把整个object/json取代,而不会去遍历其中的属性,在本例中导致了b.b1的丢失。
    于是就有了如下几行代码:

    // 遇到相同元素级属性,以后者(main)为准
    // 不返还新Object,而是main改变
    function mergeJSON (minor, main) {
      for (var key in minor) {
          
        if (main[key] === undefined) {  // 不冲突的,直接赋值
          main[key] = minor[key];
          continue;
        }
    
        // 冲突了,如果是Object,看看有么有不冲突的属性
        // 不是Object 则以main为主,忽略即可。故不需要else
        if (isJSON(minor[key])) {
          // arguments.callee 递归调用,并且与函数名解耦
          arguments.callee(minor[key], main[key]); 
        }
      }
    }
    
    // 附上工具
    function isJSON(target) {
      return typeof target == "object" && target.constructor == Object;
    }
    

    虽然只有十几行的代码,但还是挺实用。粗略的挖掘了一下搜索引擎,好像并没有更合适解决问题的代码。简单的递归思想和argument.callee琢磨一下也是有些味道的

    相关文章

      网友评论

          本文标题:原生JavaScript实现JSON合并(递归深度合并)

          本文链接:https://www.haomeiwen.com/subject/tgfnwttx.html