JavaScript:按ID设置嵌套对象值
我想知道用JavaScript更新多级对象集合成员的最佳方法是什么 以下是我收藏的简化版本:JavaScript:按ID设置嵌套对象值,javascript,object,collections,nested,set,Javascript,Object,Collections,Nested,Set,我想知道用JavaScript更新多级对象集合成员的最佳方法是什么 以下是我收藏的简化版本: this.Steps = [ { id: 1, text: "test", childSteps: [ { id: 2, text: "test"}, { id: 3, text: "test"}, { id: 4, text: "test", childSteps: [ { id: 10, text: "test"},
this.Steps = [
{ id: 1, text: "test", childSteps:
[
{ id: 2, text: "test"},
{ id: 3, text: "test"},
{ id: 4, text: "test", childSteps:
[
{ id: 10, text: "test"},
{ id: 11, text: "test"}
]}
},
{ id: 5, text: "test"},
{ id: 6, text: "test"},
{ id: 7, text: "test"},
{ id: 8, text: "test"},
{ id: 9, text: "test"}
]
}
];
理想情况是有一个调用如下的函数:
updateObjectByID(11, 'string to be set');
当我们只有一个级别的对象时,这很容易做到。但是当在多级集合上使用递归时,它变得更加困难
我目前正在使用一个函数来解析整个集合并构建字符串,如下所示:
this.Steps[0].childSteps[3].childSteps[1].text == "string to be set"
然后我对该字符串执行eval()
我相信可能有一个更干净的解决方案
顺便说一句,使用eval使我的类无法压缩
任何帮助都将不胜感激
提前感谢您可以通过id构建对象地图,以便直接访问:
var map = {};
(function recurse(steps) {
for (var i=0; i<steps.length; i++) {
var step = steps[i];
map[ step.id ] = step;
if ("childSteps" in step)
recurse(step.childSteps);
}
})(this.Steps);
function updateObjectByID(id, string) {
map[id].text = string;
}
由于使用ID调用
updateObjectById()
,因此ID必须是唯一的。那你为什么不这样改变你的结构呢:
this.Steps = [
{ id: 1, text: "test" },
{ id: 2, parent: 1, text: "test" },
{ id: 3, parent: 1, text: "test" },
{ id: 4, parent: 1, text: "test" },
{ id: 10, parent: 4, text: "test" },
{ id: 11, parent: 4, text: "test" },
{ id: 5, parent: 1, text: "test"},
{ id: 6, parent: 1, text: "test"},
{ id: 7, parent: 1, text: "test"},
{ id: 8, parent: 1, text: "test"},
{ id: 9, parent: 1, text: "test"}
]
通过这种方式,您可以轻松更新条目,如下所示:
function updateObjectByID(id, text) {
for(var i = 0; i < this.Steps.length; i++) {
if(this.Steps[i].id === id) {
this.Steps[i].text = text;
break;
}
}
}
function getChildrenByID(id) {
var array = [];
for(var i = 0; i < this.Steps.length; i++) {
if(this.Steps[i].parent === id) {
array.push(this.Steps[i]);
}
}
return array;
}
您必须递归地沿着树结构向下搜索目标为“id”的对象,并替换其文本。例如:
function updateObjectByID(obj, id, text) {
if (!obj) return;
if (obj.id === id) {
obj.text = text;
} else if ((typeof(obj)==='object') && (obj.constructor===Array)) {
for (var i=0; i<obj.length; i++) {
updateObjectByID(obj[i], id, text);
}
} else if (obj.childSteps) {
updateObjectByID(obj.childSteps, id, text);
}
}
updateObjectByID(this.Steps, 11, 'String to be set');
函数updateObjectByID(对象、id、文本){
如果(!obj)返回;
if(obj.id==id){
obj.text=文本;
}else if((typeof(obj)=='object')&(obj.constructor==数组)){
对于(var i=0;i函数updateObjectByID(id,文本){
(函数setText(步骤){
对于(var i=0;i
这是演示。“解析整个集合”…然后在此之后,您仍然必须使用eval
?不敢相信,请向我们展示该代码。事实上,我正在分析整个集合并生成字符串以更新集合成员。如果我更改对象参数,它将仅在对象的引用上更改,而不会在我的集合上更改,因为在执行递归时将childSteps作为参考发送。我无法将其粘贴为答案,因此我将编辑问题请注意this.Steps
是一个数组,而不是“根步骤”.Wow,这是一个低效的数据结构!是的,您不必直接通过属性访问任何内容,而必须始终筛选整个阵列。这也是一个有趣的解决方案,但问题是我的集合是从后端发送的,其他所有内容都像现在一样使用它,因此这将是一项艰巨的工作。woow此项工作:)。但我真的不明白怎么做!?!无论如何,非常感谢您的帮助!它们只是对步骤数组中完全相同的对象的引用。关于简化版本…该函数正在执行许多其他操作,然后只更新一个对象。它正在管理冲突的步骤(如果选择一个,则取消选择另一个等)有时,在实际找到对象之前需要对命令进行求值。我知道此解决方案非常难看且效率低下,但现在使用上面的解决方案,它将像医院一样干净。我看到MAP对象包含同一级别的所有步骤,但我不明白它是如何更改的。更新MAP[某物]时步骤成员对象值只是指向某些内存的指针。因此,this.Steps[0].childSteps[1]
和map[3]
指向完全相同的对象。如果更改该对象的属性,则无论从哪个引用查看该对象,都可以看到它。此对象与Bergis对象几乎相同。只是我没有看到地图对象。此对象也可以工作。看到这一点,我不明白为什么我的第一个版本的该函数无法工作。它们与此基本相同,但结果是更新了functions范围(obj)中的对象,但没有更新我的主集合(this.Steps)。
function updateObjectByID(obj, id, text) {
if (!obj) return;
if (obj.id === id) {
obj.text = text;
} else if ((typeof(obj)==='object') && (obj.constructor===Array)) {
for (var i=0; i<obj.length; i++) {
updateObjectByID(obj[i], id, text);
}
} else if (obj.childSteps) {
updateObjectByID(obj.childSteps, id, text);
}
}
updateObjectByID(this.Steps, 11, 'String to be set');
function updateObjectByID(id, text) {
(function setText(steps) {
for(var i = 0; i < steps.length; i++){
var step = steps[i];
if(step.id === id){
step.text = text;
}
if ("childSteps" in step){
setText(step.childSteps);
}
}
})(this.Steps);
}