0

我正在尝试使用基于 MongoDB-ish 选择器“top.middle.bottom”的属性树递归构建一个对象。还有一些 underscorejs 助手:

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

帮助和提示将不胜感激。

4

3 回答 3

2

我会选择迭代解决方案,而不是递归:

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);
于 2013-05-03T09:16:26.827 回答
2

编辑

感谢 Scott Sauyet 的建议,这是另一个版本:

function setPath(obj, [first, ...rest], val) {
    if (rest.length == 0) {
        return {...obj, [first]: val}
    }
    let nestedObj = obj[first] || {};
    return {...obj, [first]: setPath(nestedObj, rest, val)};
}

function setNestedPropertyValue(obj, field, val) {
    return setPath(obj, field.split('.'), val);
}

// example
let test_obj = {};
test_obj = setNestedPropertyValue(test_obj, "foo.bar.baz", 1);
test_obj = setNestedPropertyValue(test_obj, "foo.bar.baz1", 1);
// will output {"foo":{"bar":{"baz":1,"baz1":1}}}, while in the original version only "baz1" will be set
console.log(JSON.stringify(test_obj));

  • 这是普通的javascript
  • 它只附加属性,不会覆盖顶级对象
  • setNestedPropertyValue() 不会改变传递的对象(尽管请记住它只返回对象的浅表副本,因此某些属性可能是原始对象和新对象之间的共享引用)

我知道这是旧的,但我正是需要那种功能并且对实现不满意,所以这是我的版本:

function setNestedPropertyValue(obj, field, val) {
	if (field.indexOf(".") === -1) {
		obj[field] = val;
	} else {
		let fields = field.split(".");
		let topLevelField = fields.shift();
		let remainingFields = fields.join(".");
		if (obj[topLevelField] == null) {
			obj[topLevelField] = {};
		}
		setNestedPropertyValue(obj[topLevelField], remainingFields, val);
	}
}

// example
let test_obj = {};
setNestedPropertyValue(test_obj, "foo.bar.baz", 1);
setNestedPropertyValue(test_obj, "foo.bar.baz1", 1);
// will output {"foo":{"bar":{"baz":1,"baz1":1}}}, while in the original version only "baz1" will be set
console.log(JSON.stringify(test_obj)); 

  • 这是普通的javascript
  • 它只附加属性,不会覆盖顶级对象
  • setNestedPropertyValue() 不返回对象,因此很明显它会改变传递的对象
于 2020-04-29T13:29:26.297 回答
0

正如杰克在问题中提到的那样,我没有在else声明的最后一行返回我的对象​​。通过添加这个,它现在正在工作:

 obj[oneLevelLess] = setNestedPropertyValue( {}, remainingLevels, val);
   return obj; // Add this line
 }
于 2013-05-03T09:05:39.643 回答