元素排序例程在Firefox中有效,但在Chrome中崩溃

时间:2011-07-27 03:00:36

标签: javascript firefox dom google-chrome greasemonkey

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

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]);
}

使用Firefox作为Greasemonkey脚本的一部分,它可以正常工作。但是,在使用和不使用TamperMonkey的Chrome中,我都会这样做:

Uncaught Error: NOT_FOUND_ERR: DOM Exception 8
SortSelect:125

正如Javascript调试器的典型情况一样,错误行号是完全错误的,所以很难确切地说明为什么会破坏它以及在哪里。我愿意接受有关代码为什么会被淘汰或者有效调试它的方法的建议(我是Chrome的新手)。感谢。

3 个答案:

答案 0 :(得分:2)

你想用这段代码做什么?

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
}

答案 1 :(得分:2)

您应该使用索引迭代 options 集合,而不是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];
}

您可能从选项集合中获取非选项元素的属性,例如length。

您也不应该为选项指定“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 element的options属性是readonly,但options collection的属性却不是。{您可以直接为它们分配值(应该是对选项元素的引用)。

答案 2 :(得分:1)

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

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

此外,您不需要删除节点并重新插入它们; appendChild() works fine in all browsers to move nodes around

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

See it in action at 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 ();
    }
}