我正在寻找一种通过字符串值访问属性的好的解决方案,但是如果该属性不存在,则应该创建它。如果根结构已经定义了结构的某些部分,则属性不应被覆盖,而应合并。
例如,如果您有一个空对象,test并且想要设置一个深层结构而不使用eval。例如
test
test = {} test.foo.name = "Hallo" // <<- foo is an Object test.foo[3] = "Test" // <<- foo should remain as Object, not as Array test.foo.data[3].bar = 100 // <<- should not overwrite test.foo.name
我写了一个切实可行的解决方案,但是我猜这是很糟糕的代码:
也可以作为jsfiddle使用:https ://jsfiddle.net/gvaLzqqf/4/
Object.setValue = function(node, flatKey, value) { flatKey = flatKey.replace("[", "."); flatKey = flatKey.replace("]", ""); var parts = flatKey.split(".") var oldNode = node parts.forEach(function(key, index) { if (/^\+?(0|[1-9]\d*)$/.test(key)) { key = key * 1 if (index > 0) { var oldValue = parts[index - 1] if (!Array.isArray(oldNode[oldValue])) { oldNode[oldValue] = [] node = oldNode[oldValue] } } } if (node[key] == undefined) { node[key] = {} } oldNode = node node = node[key] }); // for each oldNode[parts[parts.length - 1]] = value return oldNode[parts[parts.length - 1]] } // function var test = {} Object.setValue(test, "foo.name", "Mr. Foo") Object.setValue(test, "foo.data[0].bar", 100) Object.setValue(test, "and.another[2].deep", 20) console.log("test = " + JSON.stringify(test)) console.log("test.foo.data[0].bar = " + test.foo.data[0].bar)
但是,有没有更好的方法来实现这一目标?
您可以拆分路径并通过遍历给定的对象来缩小路径。如果不存在对象,请使用名称或数组创建一个新属性。稍后分配值。
function setValue(object, path, value) { var way = path.replace(/\[/g, '.').replace(/\]/g, '').split('.'), last = way.pop(); way.reduce(function (o, k, i, kk) { return o[k] = o[k] || (isFinite(i + 1 in kk ? kk[i + 1] : last) ? [] : {}); }, object)[last] = value; } var test = {}; setValue(test, "foo.name", "Mr. Foo"); setValue(test, "foo.data[0].bar", 100); setValue(test, "and.another[2].deep", 20); console.log(test);