如何将两个对象与immutablejs合并?

时间:2017-01-24 11:01:59

标签: immutable.js

我想提供一个对象并从中创建一个克隆对象,但是在不影响原始对象的情况下覆盖新值。我想使用immutablejs来确保javascript对象是不可变的。

以下是我的例子:

var map1 = Immutable.fromJS({
    selector:'DYNAMIC', 
    descendants:{
        icon:'x',           
        headingLink:'DYNAMIC',              
        text:'y',       
        readMoreLink:'z'    
    }
});

var map2 = map1.mergeDeep({
    selector:'NEW VALUE',
    descendants:{
        headingLink:'NEW VALUE'
    }
}).toObject();

我期待map2输出:

{
        selector:'NEW VALUE',   
        descendants:{
            icon:'x',           
            headingLink:'NEW VALUE',                
            text:'y',       
            readMoreLink:'z'    
        }
    }

相反,我得到了ownerID和__altered等奇怪的组合:

{
        selector:'NEW VALUE',   
        descendants:
            __altered: false,
            __hash:undefined,
            __ownerID:undefined,
            _root:pt,
            size:4
        }
    }

任何有助于完成这项工作的建议都将不胜感激。如果immutablejs不能做到这一点,那么也许是另一个库。

2 个答案:

答案 0 :(得分:1)

toObject()进行浅层转换,只关闭一个键。

要将descendants Map转换为普通JS对象,您必须执行以下操作:

map2.toObject().descendants.toObject()

不是很优雅,而且非常容易出错。你可以做map2.toJS(),但是如果处理大量数据则效率很低。

理想情况下,我想知道你的用例是什么?您可以使用Immutable.js编写整个应用程序,而无需转换为纯JavaScript对象(除了与第三方组件和库一起使用)。它是一个功能强大的库,您计划对数据进行的任何转换都可以使用Immutable完成。

如果你只是在寻找一个不可变的deepMerge,你可以使用lodash中的_.merge,它甚至可以作为一个单独的模块使用。请注意,该函数中的第一个参数将被突变(合并将逐个应用于它),因此传入一个空对象{},然后传入合并源。

答案 1 :(得分:1)

我使用纯javascript提供了另一种解决方案。这适用于小物体。我不确定这会在多大程度上影响大型物体的性能,但它看起来非常快,几乎相同,如果不比lodash快一点。与lodash相比的优势在于它强制对象不可变。

var __ = {
  clone: function(obj){      
    var inst;
    if(Array.isArray(obj)){    

      inst = [];
      obj.forEach(function(item){
        inst.push(__.clone(item))
      });
    }else if(typeof obj === 'object'){            
      inst = {};
      for(key in obj){
        inst[key] = __.clone(obj[key]);
      }
      inst = Object.freeze(inst);
    }else{    
      inst = obj; // function, boolean, string, int, flt, date etc...
    }    
    // make this object immutable, so it cannot be changed.
    return inst;
  },
  recurseFreezeNew: function(objNew){
    var isArr = Array.isArray(objNew);
    if(!isArr && typeof objNew === 'object'){
      objNew = Object.freeze(objNew);
      for(key in objNew){
        objNew[key] = __.recurseFreezeNew(objNew[key]);
      }
    }else if(isArr){
            var self = this;
      objNew.forEach(function(item){
        item = __.recurseFreezeNew(item);
      });
    }
    return objNew;    
  },
  recurseMerge: function(objModel, objNew){
      var mergedResult;
      var key;

      var isModelArray = Array.isArray(objModel);
      var isNewArray = Array.isArray(objNew);

      var isModelObj = (!isModelArray && typeof objModel === 'object');
      var isNewObj = (!isNewArray && typeof objNew === 'object');

      var isBothObject = (isModelObj && isNewObj);    

      if(isBothObject){
        mergedResult = {};      
        for(key in objModel){
          if(!objNew[key]){
            mergedResult[key] = objModel[key]; //keep existing...
          }else{
            mergedResult[key] = __.recurseMerge(objModel[key], objNew[key]); // override new value
          }
        }

        for(key in objNew){
          if(!objModel[key]){
            mergedResult[key] = objNew[key]; // add new that don't exist...
          }
        }
        mergedResult = Object.freeze(mergedResult);
      }else{        
        objNew = __.recurseFreezeNew(objNew);        
        mergedResult = objNew;
      }            
      return mergedResult;
  }
};

var immutableMerge = function(){   
  var arr = Array.prototype.slice.call(arguments);
  var merged = __.clone(arr[0]);

  for(var i=1, intLen = arr.length; i < intLen; ++i){
    merged = __.recurseMerge(merged, arr[i]);
  }
  return merged;  
}


var merged = immutableMerge({
  'a':'default',
  'b':'default'
},{
  a:'NEW VALUE'
});

比较immutablejs,lodash和此自定义解决方案的示例: 查看控制台日志以查看ms差异。 8,3,1毫秒的速度。

https://jsfiddle.net/ejyvpbwx/14/