JavaScript中递归嵌套属性的创建
我正试图基于MongoDB ish选择器“top.middle.bottom”递归地构建一个具有属性树的对象。还有一些下划线帮助程序:JavaScript中递归嵌套属性的创建,javascript,recursion,Javascript,Recursion,我正试图基于MongoDB ish选择器“top.middle.bottom”递归地构建一个具有属性树的对象。还有一些下划线帮助程序: function setNestedPropertyValue(obj, fields, val) { if (fields.indexOf(".") === -1) { // On last property, set the value obj[fields] = val; return obj; // Recurse bac
function setNestedPropertyValue(obj, fields, val) {
if (fields.indexOf(".") === -1) {
// On last property, set the value
obj[fields] = val;
return obj; // Recurse back up
} else {
var oneLevelLess = _.first(fields.split("."));
var remainingLevels = _.rest(fields.split(".")).join(".");
// There are more property levels remaining, set a sub with a recursive call
obj[oneLevelLess] = setNestedPropertyValue( {}, remainingLevels, val);
}
}
setNestedPropertyValue({}, "grandpaprop.papaprop.babyprop", 1);
期望的:
{
grandpaprop: {
papaprop: {
babyprop: 1
}
}
}
结果:
undefined
帮助和提示将不胜感激。正如杰克在问题中提到的,我没有在
else
语句的最后一行返回我的对象。通过添加此项,它现在可以工作了:
obj[oneLevelLess] = setNestedPropertyValue( {}, remainingLevels, val);
return obj; // Add this line
}
正如Jack在问题中提到的,我没有在
else
语句的最后一行返回我的对象。通过添加此项,它现在可以工作了:
obj[oneLevelLess] = setNestedPropertyValue( {}, remainingLevels, val);
return obj; // Add this line
}
我会选择迭代解决方案,而不是递归:
function setNestedPropertyValue(obj, fields, val)
{
fields = fields.split('.');
var cur = obj,
last = fields.pop();
fields.forEach(function(field) {
cur[field] = {};
cur = cur[field];
});
cur[last] = val;
return obj;
}
setNestedPropertyValue({}, "grandpaprop.papaprop.babyprop", 1);
我会选择迭代解决方案,而不是递归:
function setNestedPropertyValue(obj, fields, val)
{
fields = fields.split('.');
var cur = obj,
last = fields.pop();
fields.forEach(function(field) {
cur[field] = {};
cur = cur[field];
});
cur[last] = val;
return obj;
}
setNestedPropertyValue({}, "grandpaprop.papaprop.babyprop", 1);
编辑
这是另一个版本,感谢Scott Sauyet的建议:
函数设置路径(obj,[first,…rest],val){
如果(rest.length==0){
返回{…obj[first]:val}
}
设nestedObj=obj[first]|{};
返回{…obj[first]:setPath(nestedObj,rest,val)};
}
函数setNestedPropertyValue(对象、字段、值){
返回设置路径(对象,字段分割('.'),val);
}
//范例
设test_obj={};
测试对象=设置的嵌套属性值(测试对象,“foo.bar.baz”,1);
test_obj=setNestedPropertyValue(test_obj,“foo.bar.baz1”,1);
//将输出{“foo”:{“bar”:{“baz”:1,“baz1”:1}}},而在原始版本中仅设置“baz1”
log(JSON.stringify(test_obj))代码>编辑
这是另一个版本,感谢Scott Sauyet的建议:
函数设置路径(obj,[first,…rest],val){
如果(rest.length==0){
返回{…obj[first]:val}
}
设nestedObj=obj[first]|{};
返回{…obj[first]:setPath(nestedObj,rest,val)};
}
函数setNestedPropertyValue(对象、字段、值){
返回设置路径(对象,字段分割('.'),val);
}
//范例
设test_obj={};
测试对象=设置的嵌套属性值(测试对象,“foo.bar.baz”,1);
test_obj=setNestedPropertyValue(test_obj,“foo.bar.baz1”,1);
//将输出{“foo”:{“bar”:{“baz”:1,“baz1”:1}}},而在原始版本中仅设置“baz1”
log(JSON.stringify(test_obj))
在第二个分支中没有返回obj
。也就是说,你为什么要首先使用递归?可能是@Jack的复制品,使用递归是因为我觉得它很有趣,而且(显然)我需要练习一下。@FelixKling,谢谢你提到这个问题。我猜这就是Jack暗示的方法。在第二个分支中,您不会返回obj
。也就是说,你为什么要首先使用递归?可能是@Jack的复制品,使用递归是因为我觉得它很有趣,而且(显然)我需要练习一下。@FelixKling,谢谢你提到这个问题。我想这就是杰克暗示的方法。对我来说,第三颗子弹是一个严重的负面影响。变异输入数据是魔鬼的工作!:-)我自己的非变异版本可能类似这样的函数,为字段
:const setPath=(obj,[f,…fs],val)=>f==未定义?obj:{…obj[f]:fs.length?setPath(obj[f]|{},fs,val):val}
,使用点分隔字符串进行包装:const setNestedPropertyValue=(obj,field,val)=>setPath(obj,field.split('.'),val)
。它不是特别复杂,我维护的库做得更多,但对于这里的情况来说已经足够了。@ScottSauyet哈哈,我完全同意对输入数据进行变异:)我只是说它比原始版本稍微改进了一点,这是两者的奇怪混合。谢谢你的建议!我最近只玩了一点JS,还没有遇到spread/rest操作符。我已经根据你的建议更新了我的答案。我只是更喜欢一种更详细的方法,这样我就可以了解正在发生的事情……Rest/spread可以干涸很多代码。这绝对值得研究。对我来说,第三颗子弹是一个严重的负面影响。变异输入数据是魔鬼的工作!:-)我自己的非变异版本可能类似这样的函数,为字段
:const setPath=(obj,[f,…fs],val)=>f==未定义?obj:{…obj[f]:fs.length?setPath(obj[f]|{},fs,val):val}
,使用点分隔字符串进行包装:const setNestedPropertyValue=(obj,field,val)=>setPath(obj,field.split('.'),val)
。它不是特别复杂,我维护的库做得更多,但对于这里的情况来说已经足够了。@ScottSauyet哈哈,我完全同意对输入数据进行变异:)我只是说它比原始版本稍微改进了一点,这是两者的奇怪混合。谢谢你的建议!我最近只玩了一点JS,还没有遇到spread/rest操作符。我已经根据你的建议更新了我的答案。我只是更喜欢一种更详细的方法,这样我就可以了解正在发生的事情……Rest/spread可以干涸很多代码。这绝对值得研究。