【问题标题】:Array Not renumbering数组不重新编号
【发布时间】:2012-10-28 23:35:50
【问题描述】:

我有一种情况,我必须从数组和 .splice 中删除一个 obj。发生的事情是数组没有正确重新编号,如下所示。

为了在删除数组的对象后删除数组中未定义的占位符,我执行了 [].concat()。这样做的问题是新数组没有正确编号。

以低开销正确重新编号新数组的最有效方法是什么?

for (var o = 0; o < uncheckedQue[i].childNodes.length; o += 1) {
    uncheckedQue[i].removeChild(uncheckedQue[i].childNodes[o]);
    if (uncheckedQue[i].childNodes.length < 1) {
        delete uncheckedQue[i];//remove the document fragment if has no childnodes
    };
};

 uncheckedQue = [].concat(uncheckedQue);


0: DocumentFragment
2: DocumentFragment
3: DocumentFragment
4: DocumentFragment
5: DocumentFragment
6: DocumentFragment
7: DocumentFragment
length: 8

***让我澄清一些事情。这些子节点包含在数组中的文档片段中。这些 childNode 不在 Dom 中。

这是外循环。你会注意到我为什么使用删除,所以我保持外循环的长度正确。

     for (var i = 0; i < uncheckedQue.length; i += 1) {
                 //
                 if (t.mucs === t.mucsstop) { break; };
                 for (var o = 0; o < uncheckedQue[i].childNodes.length; o += 1) {
                     uncheckedQue[i].removeChild(uncheckedQue[i].childNodes[o]);
                     t.mucs += 1;
                     if (uncheckedQue[i].childNodes.length < 1) {
                         delete uncheckedQue[i];//remove the document fragment if has no childnodes
                     };
                     if (t.mucs === t.mucsstop) { break; };
                 };
             };

【问题讨论】:

  • 这是嵌套循环的内部循环还是什么?

标签: javascript arrays indexing


【解决方案1】:

childNodes 是一个 live 节点列表,因此每次删除项目时,列表都会变短,因此您可以有效地跳过第二个节点。如果要从文档片段中删除所有 childNode,最简单的方法是继续删除 firstChild 节点,直到没有更多节点为止:

var node = uncheckedQue[i];
while (node.firstChild) {
  node.removeChild(node.firstChild);
}

另外,NodeList 是一个宿主对象,它不是一个数组,所以在它上面调用数组方法会抛出错误。

编辑

来自您的代码:

> for (var o = 0; o < uncheckedQue[i].childNodes.length; o += 1) {

用通用格式会更清楚:

for (var j=0; j < uncheckedQue[i].childNodes.length; j++) {

如果uncheckedQue是一个文档片段数组,那么:

> uncheckedQue[i].removeChild(uncheckedQue[i].childNodes[o]);

正在从片段中删除子节点。因此,现在位于childNodes[o] 的子节点是执行该语句之前位于childNodes[o + 1] 的子节点。因此,在下一次迭代中,o + 1 节点将是以前位于 o + 2 的节点。简单来说,它会移除每个第二个孩子。

还有:

> if (uncheckedQue[i].childNodes.length < 1) {

可以是:

if (!uncheckedQue[i].childNodes.length) {

因为 NodeList 的 length value 是从 0 开始的无符号整数,如果长度为零,则测试返回 true。

要从数组中删除片段,请按照 VeXii 的建议使用 Array.prototype.splice。但请注意,您必须调整索引或向后遍历数组,原因与删除活动 NodeList 的成员时相同。

你会注意到我为什么使用删除,所以我保持外循环的长度正确。

因为删除操作符不调整数组成员索引(它们只是属性名),所以你有一个稀疏数组。您可以使用拼接并随时调整索引,或者向后遍历数组,或者在最后压缩数组(这可能是性能最差的解决方案),例如

function compressArray(a) {
  for (var i=0; i<a.length; i++) {
    while (!a.hasOwnProperty(i) && a.length > i) {
      a.splice(i, 1);
    } 
  }
  return a;
}

请注意,上面修改了原始数组。将数组成员复制到新数组更简单:

function compressArray(a) {
  for (var i=0, iLen=a.length, b=[]; i<iLen; i++) {
    if (a.hasOwnProperty(i)) {
      b.push(a[i]);
    } 
  }
  return b;
}

任你选。请注意,这两种方法都不会删除值为undefined 或其他虚假值的成员,只会删除那些根本不存在的成员。

【讨论】:

  • 我没有删除子节点我正在删除 DocumentFragment。文档片段是子节点的容器。查看数组。
  • 您正在删除子节点,除非您有一个函数 removeChild 和属性 childNodes 对文档片段的操作与同名 DOM 等效项不同。查看我的编辑。
【解决方案2】:

insted 的 delete 使用 splice like

if (uncheckedQue[i].childNodes.length < 1) {
   uncheckedQue.splice(i,1)//remove the document fragment if has no childnodes
};

【讨论】:

  • 请注意,如果这样做,除非向后遍历数组,否则必须调整计数器 i,因为以前为 i + 1 的成员现在位于 i
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-24
  • 2023-02-24
  • 2011-01-23
  • 2015-02-01
相关资源
最近更新 更多