Объект NodeList, наконец, стал Iterable

Не могу не быть более взволнованным новой функцией, доступной в настоящее время в Chrome Beta (сейчас 51), которая представляет собой не что иное, как встроенную поддержку итерации NodeList 🎉

Для людей из-за пределов Интернета это может быть настолько очевидно, что всякий раз, когда вы выбираете список элементов пользовательского интерфейса, скажем так:

и вы хотите выполнить какое-то действие с каждым из них, вы можете ожидать чего-то вроде этого:

чтобы вывести это в консоль:

'www.medium.com'
'www.google.com'
'www.github.com'

но вместо этого вы получаете ... 😤😟

Uncaught TypeError: elements.forEach is not a function

Объяснение

Это много раз было головной болью для многих веб-разработчиков, поскольку, когда вы получаете их, например, из метода document.querySelectorAll, вы получаете коллекцию…

Объекты NodeList - это коллекции узлов

Объяснение на самом деле очень простое, и оно относится к наследованию прототипа, которое использует Javascript, проблема в том, что объект NodeList не является массивом и не содержит forEach в своем прототипе, на самом деле он не содержит никаких методов массива. То же самое происходит с объектом arguments, который, опять же, не является массивом и не содержит таких методов ... в любом случае, вам нет оправдания, чтобы по-прежнему использовать объект arguments, поскольку параметр rest синтаксис позволяет вам представлять неопределенное количество аргументов в виде массива, что вам и нужно 😼.

Поиск метода массива

myArray → Array.prototype → Object.prototype → null

Поиск метода NodeList

myNodeList → NodeList.prototype → Object.prototype → null

Symbol.iterator

Хорошей новостью является то, что Chrome внес следующие изменения в NodeList, проверьте это на странице статуса хрома.

Добавляет `Symbol.iterator` к любому интерфейсу DOM, содержащему индексированное средство получения свойства и свойство length.

Это означает, что благодаря Symbol.iterator теперь любой объект, реализующий этот протокол, можно повторять, как будто это массив. Просто откройте консоль браузера и введите:

Array.prototype[Symbol.iterator]
String.prototype[Symbol.iterator]
NodeList.prototype[Symbol.iterator]

вы быстро поймете, что теперь все они являются повторяемыми объектами.

Также появилась возможность использовать оператор распространения с объектами NodeList:

и оператор for of, который вызывает пользовательский перехватчик итераций с операторами, которые должны выполняться для значения каждого отдельного свойства:

Обходные пути, обходные пути, обходные пути…

А теперь вернемся к реальности на секунду ...

Срез массива

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

jQuery каждый

Стандартная библиотека javascript, AKA jQuery, уже несколько лет назад неплохо решила эту проблему, все, что вам нужно сделать, это использовать метод each. Обратите внимание, что индекс является первым аргументом вместо элемента.

Array.from

Это тоже неплохо, метод Array.from создает новый экземпляр Array из объекта, подобного массиву или повторяемого объекта. Плохая новость - это снова текущая поддержка браузеров ...

Расширение прототипа

Долгое время это считалось плохой практикой, лично я также не люблю добавлять новые методы к нативным объектам. Но! В данном случае это мое любимое решение, поскольку имеет смысл сделать итерации NodeList по умолчанию, и это то, чего вы ожидаете всякий раз, когда вы извлекаете элементы из DOM.

Заключение

Для большинства разработчиков это может показаться мелочью, но я думаю, что на самом деле важно, чтобы браузеры следовали этому направлению, заставляя вещи вести себя так, как ожидают разработчики, и исправляя неожиданные поведения, даже если они такие простые.