使用索引数组向对象数组添加条目

问题描述 投票:0回答:1

我有以下场景:我有一个对象数组(TreeItems),其中可能包含嵌套数组。我还有另一个带有索引的数组。现在我想使用索引数组更改 TreeItems 数组以访问特定的树项目,并且根据是否存在名为“items”的嵌套数组,我想附加现有数组或添加新数组。最重要的是,我想摆脱邪恶的评估。

因此,在我的示例中,我尝试在 TreeItems[4][0][0] 添加一个新条目,但括号中的索引应该从索引数组中动态添加,但我不太清楚如何执行此操作。

我当然已经搜索过并找到了这个,但它对我来说不太有用。

任何帮助将不胜感激。

const TreeItems = [
  { text: "Lvl 0", items: [{ text: "Lvl 0-0" }, { text: "Lvl 0-1" }] },
  { text: "Lvl 1" },
  { text: "Lvl 2", items: [{ text: "Lvl 2-0" }, { text: "Lvl 2-1" }] },
  { text: "Lvl 3" },
  {
    text: "Lvl 4",
    items: [
      {
        text: "Lvl 4-0",
        items: [
          {
            text: "Lvl 4-0-0",
            items: [{ text: "Lvl 4-0-0-0" }, { text: "Lvl 4-0-0-1" }, { text: "Lvl 4-0-0-2" }],
          },
          { text: "Lvl 4-0-1" },
          { text: "Lvl 4-0-2" },
        ],
      },
    ],
  },
];

const indexes = [4,0,0];
let comString = '';
for(let i = 0; i < indexes.length; i++) {
  if(i === 0) {
    comString = "TreeItems[" + indexes[i] + "]";
  } else {
    comString += ".items[" + indexes[i] + "]";
  }
}

if(eval(comString).items !== undefined) {
  eval(comString).items.push({"text": "Test-item-appended"});
} else {
  eval(comString).items = [{"text": "Test-items-added"}]
}
console.log(comString);
console.log(eval(comString).items);
console.log(TreeItems);

javascript arrays typescript multidimensional-array eval
1个回答
0
投票

您不必使用

eval
或任何类型的动态代码生成来执行此操作。事实上,除非您明确希望执行一段外部 JavaScript 代码,否则不存在需要使用
eval
的编程问题。

如果您想使用索引数组作为路径来访问

TreeItems
的嵌套子级,您可以创建一个变量,用于将子级存储在深度
n
处,从 0 开始,然后用位于 的子级重复覆盖它深度
n + 1
,直到您考虑了路径中的所有索引:

function getTreeItem(path) {
    // get first child, whose index is at path[0]
    let currentChild = TreeItems[path[0]];
    
    // for indices at path[1] and further, overwrite currentChild with the next child
    for (let i = 1; i < path.length; i++)
        currentChild = currentChild.items[path[i]];
    
    return currentChild;
}

请注意,使用 for 循环和 let 语句有点冗长,并且违背了现代 JavaScript 的编码风格。执行此操作的正确方法是使用 Array.prototype.reduce,如您找到的答案中所建议的。最初的问题是关于数组的数组,而在本例中,您正在访问具有名为

items
的属性的对象数组,并且您的函数必须考虑到这一点。

以下代码在功能上等同于上面的代码:

function getTreeItem(path) {
    return path.reduce(
        (currentChild, currentPathIndex, depth) => {
            // if currentPathIndex is path[0], set currentChild to the currentPathIndex-th child of TreeItems
            if (depth == 0)
                return TreeItems[currentPathIndex];
        
            // otherwise, set currentChild to the currentPathIndex-th child of currentChild.items
            return currentChild.items[currentPathIndex];
        },
        // let the initial currentChild be null and the initial depth be 0
        null
    );
}

在 MDN 上了解有关 Array.prototype.reduce 的更多信息。

一旦获得了对父节点的引用,您就可以按照问题中提出的完全相同的方式向其添加项目:

function addTreeItem(parentPath, text) {
    const parent = getTreeItem(parentPath);
    
    if (parent.items)
        parent.items.push({text})
    else
        parent.items = [{text}];
}

addTreeItem([4, 0, 0, 0], "added item");
addTreeItem([4, 0, 0, 0], "appended item");
© www.soinside.com 2019 - 2024. All rights reserved.