元素排序例程在Firefox中工作,但在Chrome中崩溃

Element sort routine works in Firefox, but crashes in Chrome

本文关键字:但在 Chrome 崩溃 工作 元素 例程 Firefox 排序      更新时间:2023-09-26

我编写了以下例程来对select中的option元素进行排序:

function SortSelect(select)
{
    var tmpAry = new Array();
    for (var i in select.options)
        tmpAry[i] = select.options[i];
    tmpAry.sort(function(opta, optb)
    {
        if (opta.id > optb.id) return  1;
        if (opta.id < optb.id) return -1;
        return 0;
    });
    while (select.options.length > 0)
        select.options[0] = null;
    for (var i in tmpAry)
        select.appendChild(tmpAry[i]);
}

作为Greasemonkey脚本的一部分,它在Firefox中工作得很好。然而,在Chrome中,无论有没有TamperMonkey,我得到这个:

Uncaught Error: NOT_FOUND_ERR: DOM Exception 8
SortSelect:125

与Javascript调试器的典型情况一样,错误行号完全错误,因此很难准确确定为什么会出错以及在哪里出错。我是开放的建议,为什么代码是调试或方法有效地调试它(我是新的Chrome)。谢谢。

应该使用索引来遍历选项集合,而不是使用for..in循环。如下:

for (var i in select.options) {
  tmpAry[i] = select.options[i];
应:

var options = select.options;
for (var i=0, iLen=options.length; i<iLen; i++) {
  tmpAry[i] = options[i];
}

您可能会从选项集合中获得不是选项元素的属性,例如长度。

你也不应该给一个选项赋值"null"。如果要删除所有选项,只需将选项的长度设置为零:

var options.length = 0;

最后,您应该使用索引遍历tmpAray,因为for..in 不会在每个浏览器中以相同的顺序返回选项,并且可能返回非数字可枚举属性(如果有),使用索引。此外,您可以将该选项分配回select的选项集合,不需要使用appendChild:

select.options.length = 0;
for (var i=0, iLen=tmpAry.length; i<iLen; i++) {
    select.options[i] = tmpAry[i];
}

如果你没有删除任何选项,你应该能够按照新的顺序分配它们,但有些浏览器不能处理这个问题,所以最好先删除它们。

编辑

注意,select元素的options属性是只读的,而options集合的属性则不是。你可以直接给它们赋值(应该是对option元素的引用)

你想用这段代码做什么?

while (select.options.length > 0)
    select.options[0] = null;

如果答案是你试图清除所有的选择选项,这似乎很危险。我可以看出这很容易成为一个无限循环。

在我看来,这样会安全得多:

for (var i = select.options.length - 1; i > 0; i--) {
    select.remove(i);
}

然后,有一个select.options.add()方法将它们添加回去。


仅供参考,在数组或伪数组上使用这种结构也被认为是有风险的做法:

for (var i in select.options)
for (var i in tmpAry)

,因为除了数组元素之外,它还可以拾取添加到对象中的属性。

输入更多,但使用更安全:

for (var i = 0, len = tmpAry.length; i < len; i++) {
   // code here
}

这些行可能导致无限循环或访问冲突:

while (select.options.length > 0)
    select.options[0] = null;

同样,您不需要删除节点并重新插入它们;appendChild()在所有浏览器中都可以很好地移动节点。

因此,这段代码可以工作,并且应该比删除和重新创建节点(这也可以丢弃任何事件侦听器)更有效。:

查看jsFiddle的实际操作

function SortSelect (select)
{
    var tmpAry  = [];
    for (var J = select.options.length - 1;  J >= 0;  --J)
        tmpAry.push (select.options[J] );
    tmpAry.sort ( function (opta, optb) {
        if (opta.id > optb.id) return  1;
        if (opta.id < optb.id) return -1;
        return 0;
    } );
    while (tmpAry.length) {
        select.appendChild ( document.getElementById (tmpAry[0].id) );
        tmpAry.shift ();
    }
}
相关文章: