Фильтровать или отображать нодлисты в ES6

87

Каков наиболее эффективный способ фильтрации или сопоставления нодлистов в ES6?

Основываясь на моих чтениях, я бы использовал один из следующих вариантов:

[...nodelist].filter

или

Array.from(nodelist).filter

Какой из них вы бы порекомендовали? А есть ли способы лучше, например, без использования массивов?

Кристоф
источник
2
По сути, оба метода делают одно и то же. Если вы используете babel, тогда [...coll]просто вызовет Array.from(coll)все, что не является Array.
Леонид Бесчастный
FWIW, ...синтаксис может не поддерживаться старыми IDE, пока Array.from()это обычный метод.
Марат Таналин

Ответы:

126
  • [...nodelist] сделает массив из объекта, если объект является итеративным.
  • Array.from(nodelist)сделает массив из объекта, если объект является повторяемым или если объект подобен массиву (имеет .lengthчисловые реквизиты)

Ваши два примера будут идентичны, если они NodeList.prototype[Symbol.iterator]существуют, потому что оба случая охватывают итерации. Если ваша среда не была настроена таким образом, чтобы ее NodeListможно было итерировать, ваш первый пример завершится ошибкой, а второй - успешным. Babelв настоящее время не обрабатывает это дело должным образом .

Так что, если ваш NodeListитеративный, действительно зависит от вас, что вы используете. Скорее всего, я выберу в индивидуальном порядке. Одним из преимуществ Array.fromявляется то, что он принимает второй аргумент функции сопоставления, тогда как первый [...iterable].map(item => item)должен был бы создать временный массив, но Array.from(iterable, item => item)этого не сделал . Однако, если вы не отображаете список, это не имеет значения.

логанфсмиф
источник
17

TL; DR;

Array.prototype.slice.call(nodelist).filter

Метод slice () возвращает массив. Этот возвращаемый массив представляет собой неглубокую копию коллекции (NodeList), поэтому он работает быстрее, чем Array.from (), поэтому он работает так же быстро, как Array.from ()

Элементы исходной коллекции копируются в возвращаемый массив следующим образом:

  • Для ссылок на объекты (а не на фактический объект) срез копирует ссылки на объекты в новый массив. И исходный, и новый массивы ссылаются на один и тот же объект. Если объект, на который имеется ссылка, изменяется, изменения видны как для нового, так и для исходного массивов.
  • Для строк, чисел и логических значений (не объектов String, Number и Boolean) срез копирует значения в новый массив. Изменения строки, числа или логического значения в одном массиве не влияют на другой массив.

Краткое объяснение аргументов

Array.prototype.slice (beginIndex, endIndex)

  • принимает необязательные аргументы beginIndex и endIndex. Если они не предоставлены, срезы используют beginIndex == 0, таким образом, он извлекает все элементы из коллекции.

Array.prototype.slice.call (пространство имен, beginIndex, endIndex)

  • принимает объект в качестве первого аргумента. Если мы используем коллекцию как объект, это буквально означает, что мы вызываем метод slice непосредственно из этого пространства имен объекта. Slice ()
Серж Селецкий
источник
2
Спасибо за этот фрагмент кода, который может оказать некоторую немедленную помощь. Правильное объяснение значительно повысило бы его ценность в долгосрочной перспективе, показав, почему это хорошее решение проблемы, и сделало бы его более полезным для будущих читателей, задающих другие похожие вопросы. Отредактируйте свой ответ, чтобы добавить пояснения, включая сделанные вами предположения.
Максимилиан Питерс
Мне интересно, поддерживает ли это IE, поскольку Array.fromнет. Пора найти машину IE. Теперь я действительно запутался, потому что смог использовать Array.from в IE10 и IE11: \. Этот метод работает в IE10 + 11, но меня не облегчает работа с Array.from, когда вся документация говорит об обратном.
CTS_AE
Array.fromу меня не работает в IE11 Объект не поддерживает свойство или метод from
Fus Ro Dah
Спасибо, у меня это сработало на старой реализации JavaScript
Вик Сидублью
1
Array.fromтакже возвращает мелкую копию. Поэтому я не понимаю, как вы пришли к выводу, что он работает быстрее, чем Array#slice.
Роберт
9

Я нашел ссылку, которая используется mapнепосредственно в NodeList по

Array.prototype.map.call(nodelist, fn)

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

Говон
источник
2

Как насчет этого:

// Be evil. Extend the prototype.
if (window.NodeList && !NodeList.prototype.filter) {
  NodeList.prototype.filter = Array.prototype.filter;
}

// Use it like you'd expect:
const noClasses = document
  .querySelectorAll('div')
  .filter(div => div.classList.length === 0)

Это тот же подход, который упоминается в документации MDN для NodeList.forEach (в разделе «Polyfill»), он работает для IE11 , Edge, Chrome и FF.

панепетер
источник