Как определить HTMLCollection/NodeList в JavaScript?

Я не уверен, что моя текущая реализация доступна все время:

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

Следующее должно возвращать true, если узлы имеют тип NodeList

NodeList.prototype.isPrototypeOf(nodes)

@DavidSpector, для HTMLCollection вы также можете использовать:

HTMLCollection.prototype.isPrototypeOf(collection)

Ответ 2

Я бы структурировал код по-другому:

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
  • использовать квадратные скобки для индексации в список
  • Я не думаю, что попытка/улов действительно необходима, но это может быть неправильно - вы решаете
  • проверьте nodeType вместо tagName, поскольку текстовые узлы или комментарии не имеют имени
  • добавьте больше проверок в цепочку &&, если вы соответствуете

Ответ 3

script

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
  */
}

Ответ 4

Вот как проверить, является ли объект NodeList в современных браузерах:

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

Ответ 6

Этот ответ, вероятно, действительно очень поздний, но....

if (nodes == '[object NodeList]') {
  // It a nodeList
}

Ответ 7

Я создал контрольный показатель всех ответов здесь, чтобы увидеть, что лучше всего одобрить в скорости. Выключает NodeList.prototype.isPrototypeOf(nodes), безусловно, самый быстрый. Но в обычных случаях использования nodes instanceof NodeList тоже будет хорошо.

Лично я бы просто не выбрал функцию isNodeList, потому что ее медленные, пользовательские и слишком большие накладные расходы.