Почему nodelist не имеет forEach?



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



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

654   10  

10 ответов:

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

посмотреть nodeList forEach () на MDN.

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

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

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

проблема была код, который неверно предположил, что instanceof означает, что экземпляр был массивом в сочетании с массивом.прототип.функция 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 класс, который был настоящим подкласс Массив, и будет использоваться как "новый NodeList". Однако, это было удалено из стандарта DOM, по крайней мере, на данный момент, поскольку это было невозможно реализовать еще по целому ряду технических и технических причин.

можно сделать

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

    // Your code here.

} );

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

  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

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

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

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

от MDN:

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

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

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

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

forEach, map и подобные-это собственные свойства массива.прототип объект.

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

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

список узлов.прототип содержит элемент метода, но ни один из Матрица.прототип методы, поэтому они не могут быть использованы на NodeLists.

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

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

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

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

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

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

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

Посмотреть MDN Link

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

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

как Array.from() метод shimmable, вы можете использовать его в ES5 код такой

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

для получения дополнительной информации см. MDN

мое решение:

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

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

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

Проверьте MDN для Списке_узлов.по каждому элементу спецификация.

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

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

[].forEach.call(NodeList, function(item, index, array) {
    // code block here
});

Comments

    Ничего не найдено.