如何在JavaScript中检测HTMLCollection/NodeList?

35

我不确定我的当前实现始终可用:

function isNodeList(nodes) {
    var result = Object.prototype.toString.call(nodes);
    // modern browser such as IE9 / firefox / chrome etc.
    if (result === '[object HTMLCollection]' || result === '[object NodeList]') {
        return true;
    }
    //ie 6/7/8
    if (typeof(nodes) != 'object') {
        return false;
    }
    // detect length and item 
    if (!('length' in nodes) || !('item' in nodes)) {
        return false;
    }
    // use the trick NodeList(index),all browsers support
    try {
        if (nodes(0) === null || (nodes(0) && nodes(0).tagName)) return true;
    }
    catch (e) {
        return false;
    }
    return false;
}

常见情况是{length:1,item:function(){return [];}}
在Chrome/Safari/Opera中,结果为“[object NodeList]”。
在Firefox和IE 9中,结果为“[object HTMLCollection]”。

哪个是标准值?


1
如何在IE中检查一个对象是否是NodeList的实例? - Matt Ball
@Matt Ball -- 在ie6中,typeof nodes.item返回的是“字符串”,而不是“函数”。因此我们需要更多的检测。 - simon xu
7个回答

52

如果 nodes 的类型是 NodeList,则以下内容应返回true

NodeList.prototype.isPrototypeOf(nodes)

@DavidSpector,对于HTMLCollection,您同样可以使用:

HTMLCollection.prototype.isPrototypeOf(collection)

是的,但这并没有回答问题:如何判断一个对象是否为HTML集合。 - David Spector
3
ES lint 安全版本:Object.prototype.isPrototypeOf.call(NodeList.prototype, nodes) - Sanyam Jain

25

我会以不同的方式构建代码:

function isNodeList(nodes) {
    var stringRepr = Object.prototype.toString.call(nodes);

    return typeof nodes === 'object' &&
        /^\[object (HTMLCollection|NodeList|Object)\]$/.test(stringRepr) &&
        (typeof nodes.length === 'number') &&
        (nodes.length === 0 || (typeof nodes[0] === "object" && nodes[0].nodeType > 0));
}

注意事项:

  • 减少返回路径可以使代码更易读
  • 如果可能的话,坚持使用一种逻辑类型(即使用较少的否定检查)
  • "item" 不一定在 nodeList 中
  • 使用 hasOwnProperty() 而不是 in
  • 使用方括号索引列表
  • 我认为不需要使用 try/catch,但这可能是错误的 - 由您决定
  • 检查 nodeType 而不是 tagName,因为文本节点或注释没有名称
  • 如果需要,可以向 && 链中添加更多的检查

有时会在现场出现此错误:'0.nodeType' 为空或不是对象。有什么想法是什么可能会被忽略了吗? - tester
1
为什么要使用返回true/false语句...只需返回您在if语句中测试的值即可。即删除if语句和返回语句,只需用return语句替换即可。 - timoxley
2
在我的Chrome浏览器中,nodes.hasOwnProperty('length')返回false。也许使用typeof nodes.length === 'number'更好? - Max G J Panas
1
@MaxGJPanas 是的,那时候可以用,但显然事情已经变了。我已经相应地修改了我的答案,感谢你提醒。 - Tomalak

16

以下是如何在现代浏览器中测试对象是否为NodeList:

if (nodes instanceof NodeList) {
  // It's a NodeList object
}

顺便说一下,这个方法非常慢。 - Frondor
6
@Frondor为什么这样做? - Pavel Hasala

13

脚本:

Element.prototype.isNodeList = function() {return false;}
NodeList.prototype.isNodeList = HTMLCollection.prototype.isNodeList = function(){return true;}

使用方法

var d; // HTMLCollection|NodeList|Element
if(d.isNodeList()){
  /*
    it is HTMLCollection or NodeList
    write your code here
  */
}else{
  /*
    it is not HTMLCollection and NodeList
    write your code here
  */
}

11

检查变量是HTMLCollection还是DOM元素

  var foo = document.getElementById('mydiv');
  var foo2 = document.getElementsByClassName('divCollection');
  console.log(foo instanceof HTMLElement);
  console.log(foo instanceof HTMLCollection);

@Horay 希望这能帮到你。 - koech
谢谢!是的,它确实有帮助! 我该如何检查它不是 instanceof HTMLCollection?我在哪里放置(!)感叹号? - Horay
好的解决方案...谢谢。 @Horay 可能有点晚了,但是...如果 (!(stuff instanceof That)) { ... } - eglaf
如果您使用标准样式,实际上是 foo instanceof window.HTMLCollection。- https://standardjs.com/ - user670839

5
这个答案可能真的非常晚了,但是....
if (nodes == '[object NodeList]') {
  // It's a nodeList
}

4
这在IE8中无法工作 =( 你会得到"[object Object]"。 - Justin

0

我在这里创建了一个基准测试,来看看什么是速度最快的批准方式。结果证明,在速度上,NodeList.prototype.isPrototypeOf(nodes) 是远远最快的。但在正常情况下,nodes instanceof NodeList 也是可以的。

个人而言,我只是不会选择 isNodeList 函数,因为它太慢、自定义,并且有太多额外开销。


我更喜欢使用 (!!nodes.length) // true - darcher
检查 length 属性是否可用与检查变量是否为 NodeList 类型没有任何关系。 - eisbehr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接