如何使用 immutablejs 合并两个对象?
How to do I merge two objects with immutablejs?
我想提供一个对象并从中创建一个克隆对象,但用新值覆盖而不影响原始对象。我想使用 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 不能做到这一点,那么也许有一个替代库可以。
toObject()
进行浅层转换,仅按下一个键。
要将 descendants
Map 转换为普通 JS 对象,您必须执行以下操作:
map2.toObject().descendants.toObject()
不是很优雅,而且很容易出错。你可以只做 map2.toJS()
,但如果处理大量数据,效率会很低。
理想情况下,我想知道您的用例是什么?您可以使用 Immutable.js 编写整个应用程序,而无需转换为普通 JavaScript 对象(与第 3 方组件和库一起使用除外)。这是一个功能强大的库,您计划对数据进行的任何转换都可以使用 Immutable 完成。
如果您只是在寻找不可变的 deepMerge
,您可以使用 lodash 中的 _.merge
,它甚至可以作为单独的模块使用。请注意,该函数中的第一个参数将发生变化(合并一个一个地应用于它),因此传入一个空对象,{}
,然后是你的合并源。
我提供了一个替代解决方案,使用纯 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 毫秒速度。
我想提供一个对象并从中创建一个克隆对象,但用新值覆盖而不影响原始对象。我想使用 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 不能做到这一点,那么也许有一个替代库可以。
toObject()
进行浅层转换,仅按下一个键。
要将 descendants
Map 转换为普通 JS 对象,您必须执行以下操作:
map2.toObject().descendants.toObject()
不是很优雅,而且很容易出错。你可以只做 map2.toJS()
,但如果处理大量数据,效率会很低。
理想情况下,我想知道您的用例是什么?您可以使用 Immutable.js 编写整个应用程序,而无需转换为普通 JavaScript 对象(与第 3 方组件和库一起使用除外)。这是一个功能强大的库,您计划对数据进行的任何转换都可以使用 Immutable 完成。
如果您只是在寻找不可变的 deepMerge
,您可以使用 lodash 中的 _.merge
,它甚至可以作为单独的模块使用。请注意,该函数中的第一个参数将发生变化(合并一个一个地应用于它),因此传入一个空对象,{}
,然后是你的合并源。
我提供了一个替代解决方案,使用纯 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 毫秒速度。