Почему для нодлиста нет?

Я работал над небольшим script, чтобы изменить внутренний текст <abbr> элементов, но обнаружил, что nodelist не имеет метода forEach. Я знаю, что nodelist не наследует от Array, но похоже, что forEach был бы полезным методом? Есть ли какая-то конкретная проблема с реализацией, о которой я не знаю, не позволяет добавить forEach в nodelist?

Примечание. Я знаю, что Dojo и jQuery имеют forEach в той или иной форме для своих нодлистов. Я не могу использовать либо из-за ограничений.

Ответ 1

Ни один из этих ответов не объясняет, почему NodeList не наследует от Array, что позволяет ему иметь forEach и все остальные.

Ответ найден в этом обсуждении темы. Короче говоря, он разбивает Интернет:

Проблема заключалась в том, что неверно предполагаемый экземпляр был означать, что экземпляр был массивом в сочетании с Array.prototype.concat.

В Google Closure Library произошла ошибка, из-за которой почти все приложения Google потерпели неудачу. Библиотека была обновлена, как только это было обнаружено, но там все еще может быть код, который делает такое же неправильное предположение в сочетании с concat.

То есть, какой-то код сделал что-то вроде

if (x instanceof Array) {
  otherArray.concat(x);
} else {
  doSomethingElseWith(x);
}

Однако concat будет обрабатывать "реальные" массивы (а не instanceof Array) иначе, чем другие объекты:

[1, 2, 3].concat([4, 5, 6]) // [1, 2, 3, 4, 5, 6]
[1, 2, 3].concat(4) // [1, 2, 3, 4]

так что это означает, что приведенный выше код сломался, когда x был NodeList, потому что до того, как он спустился по пути doSomethingElseWith(x), тогда как после этого он пошел по пути otherArray.concat(x), что сделало что-то странное, так как x wasn 't реальный массив.

В течение некоторого времени было предложение для класса Elements, который был реальным подклассом Array и использовался как "новый NodeList". Тем не менее, это было удалено из стандарта DOM, по крайней мере на данный момент, поскольку пока не представляется возможным реализовать множество технических и технических требований связанных причин.

Ответ 2

Вы можете сделать

Array.prototype.forEach.call (nodeList, function (node) {

    // Your code here.

} );

Ответ 3

Вы можете создать новый массив узлов.

  var nodeList = document.getElementsByTagName('div'),

      nodes = Array.prototype.slice.call(nodeList,0); 

  // nodes is an array now.
  nodes.forEach(function(node){ 

       // do your stuff here.  

  });

Примечание. Это просто список/массив node ссылок, которые мы здесь создаем, не дублируем узлы.

  nodes[0] === nodeList[0] // will be true

Ответ 4

Короче говоря, его конфликт конструкции реализует этот метод.

Из MDN:

Почему я не могу использовать forEach или карту в NodeList?

NodeList используются очень похоже на массивы, и было бы заманчиво используйте методы Array.prototype. Это, однако, невозможно.

JavaScript имеет механизм наследования, основанный на прототипах. массив экземпляры наследуют методы массива (например, forEach или map), поскольку их цепочка прототипов выглядит следующим образом:

myArray --> Array.prototype --> Object.prototype --> null ( Цепочка прототипа объекта может быть получена путем вызова нескольких раз Object.getPrototypeOf)

forEach, map и подобные являются собственными свойствами Array.prototype объект.

В отличие от массивов цепочка прототипов NodeList выглядит следующим образом:

myNodeList --> NodeList.prototype --> Object.prototype --> null

NodeList.prototype содержит метод item, но ни один из Array.prototype, поэтому их нельзя использовать в NodeLists.

Источник: https://developer.mozilla.org/en-US/docs/DOM/NodeList (прокрутите вниз до Почему я не могу использовать forEach или карту в NodeList?)

Ответ 5

Никогда не говорите никогда, это 2016 и объект NodeList реализовал метод forEach в последнем хроме (v52.0.2743.116).

Слишком рано использовать его в производстве, поскольку другой браузер еще не поддерживает это (проверенный FF 49), но я бы предположил, что это будет стандартизировано в ближайшее время.

Ответ 6

Если вы хотите использовать forEach в NodeList, просто скопируйте эту функцию из массива:

NodeList.prototype.forEach = Array.prototype.forEach;

Вот и все, теперь вы можете использовать его так же, как для Array:

document.querySelectorAll('td').forEach(function(o){
   o.innerHTML = 'text';
});

Ответ 7

NodeList является частью DOM API. Посмотрите на привязки ECMAScript, которые также применимы к JavaScript. http://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html. Свойство nodeList и свойство длины для чтения и элемент (индекс) возвращают node.

Ответ: вам нужно итератировать. Альтернативы нет. Foreach не будет работать. Я работаю с привязками API Java DOM и имею ту же проблему.

Ответ 8

Мое решение:

//foreach for nodeList
NodeList.prototype.forEach = Array.prototype.forEach;
//foreach for HTML collection(getElementsByClassName etc.)
HTMLCollection.prototype.forEach = Array.prototype.forEach;