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

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

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

79 голосов | спросил Snakes and Coffee 17 62012vEurope/Moscow11bEurope/MoscowSat, 17 Nov 2012 23:05:47 +0400 2012, 23:05:47

10 ответов


0

NodeList теперь имеет forEach () во всех основных браузерах

См. nodeList forEach () в MDN .

Оригинальный ответ

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

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

  

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

     

В закрывающей библиотеке Google произошла ошибка, из-за которой почти все приложения 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 не был настоящим массивом.

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

ответил Domenic 19 32014vEurope/Moscow11bEurope/MoscowWed, 19 Nov 2014 21:25:16 +0300 2014, 21:25:16
0

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

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

    // Your code here.

} );
ответил akuhn 15 MaramSat, 15 Mar 2014 02:07:34 +04002014-03-15T02:07:34+04:0002 2014, 02:07:34
0

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

  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.  

  });

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

  nodes[0] === nodeList[0] // will be true
ответил sbr 14 MaramThu, 14 Mar 2013 02:58:38 +04002013-03-14T02:58:38+04:0002 2013, 02:58:38
0

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

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

ответил maioman 25 AM000000120000000931 2016, 00:25:09
0

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

Из MDN:

  

Почему я не могу использовать forEach или map в 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 или map в NodeList? )

ответил Matt Lo 17 62012vEurope/Moscow11bEurope/MoscowSat, 17 Nov 2012 23:10:05 +0400 2012, 23:10:05
0

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

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

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

document.querySelectorAll('td').forEach(function(o){
   o.innerHTML = 'text';
});
ответил AlexTR 31 Maypm14 2014, 22:30:24
0

В ES2015 теперь вы можете использовать метод forEach для nodeList.

document.querySelectorAll('abbr').forEach( el => console.log(el));

См. ссылку на MDN

Однако, если вы хотите использовать коллекции HTML или другие объекты, похожие на массивы, в es2015 вы можете использовать метод Array.from(). Этот метод принимает массивоподобный или повторяемый объект (включая nodeList, коллекции HTML, строки и т. Д.) И возвращает новый экземпляр Array. Вы можете использовать это так:

const elements = document.getElementsByTagName('abbr');
Array.from(elements).forEach( el => console.log(el));

Поскольку метод Array.from() может быть изменяемым, его можно использовать в коде es5 следующим образом

var elements = document.getElementsByTagName('abbr');
Array.from(elements).forEach( function(el) {
    console.log(el);
});

Подробнее см. в MDN страница.

Чтобы проверить текущую поддержку браузера .

ИЛИ

Другой способ es2015 - использовать оператор распространения.

const elements = document.getElementsByTagName('abbr');
(elements).forEach( el => console.log(el));

это может быть записано в виде одной строки:

(document.getElementsByTagName('abbr')).forEach( el => console.log(el));

оператор распространения MDN

Оператор распространения - поддержка браузера

ответил Mishel Tanvir Habib 15 J0000006Europe/Moscow 2018, 08:31:17
0

Мое решение:

//foreach for nodeList
NodeList.prototype.forEach = Array.prototype.forEach;
//foreach for HTML collection(getElementsByClassName etc.)
HTMLCollection.prototype.forEach = Array.prototype.forEach;
ответил Bakos Bence 12 72017vEurope/Moscow11bEurope/MoscowSun, 12 Nov 2017 22:14:46 +0300 2017, 22:14:46
0

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

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

ответил randominstanceOfLivingThing 17 62012vEurope/Moscow11bEurope/MoscowSat, 17 Nov 2012 23:14:27 +0400 2012, 23:14:27
0
  

Проверьте MDN для спецификации NodeList.forEach . .

NodeList.forEach(function(item, index, nodeList) {
    // code block here
});

В IE используйте ответ акуна :

[].forEach.call(NodeList, function(item, index, array) {
    // code block here
});
ответил VesperX 2 +03002018-10-02T02:04:52+03:00312018bEurope/MoscowTue, 02 Oct 2018 02:04:52 +0300 2018, 02:04:52

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132