Фильтровать или сопоставлять нодлисты в ES6

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

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

[...nodelist].filter

or

Array.from(nodelist).filter

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


person Christophe    schedule 24.09.2015    source источник
comment
По сути, оба метода делают одно и то же. Если вы используете babel, то [...coll] будет просто вызывать Array.from(coll) для всего, что не является Array.   -  person Leonid Beschastny    schedule 24.09.2015
comment
FWIW, синтаксис ... может не поддерживаться более старыми IDE, а Array.from() — это обычный метод.   -  person Marat Tanalin    schedule 24.09.2015


Ответы (5)


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

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

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

person loganfsmyth    schedule 24.09.2015
comment
Просто обратите внимание, что Array.from не поддерживается в IE. - person Yann Dìnendal; 15.02.2021
comment
@YannDìnendal Это правда, но этот вопрос касается ES6, а IE вообще почти не поддерживает ES6, так что это уже тупик. - person loganfsmyth; 17.02.2021
comment
Да, это правда. :) Я должен был уточнить, что я имел в виду: если вы полагаетесь на Babel для преобразования es6 в es5, он по умолчанию не будет использовать методы прототипа polyfill. Так что просто кое-что, о чем нужно знать. :) - person Yann Dìnendal; 19.02.2021

TL;DR;

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

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

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

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

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

Array.prototype.slice(beginIndex, endIndex)

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

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

  • принимает объект в качестве первого аргумента. Если мы используем коллекцию как объект, это буквально означает, что мы вызываем метод slice непосредственно из этого объекта namespace.slice().
person Serge Seletskyy    schedule 13.04.2018
comment
Спасибо за этот фрагмент кода, который может предоставить некоторую ограниченную немедленную помощь. Надлежащее объяснение значительно повысило бы его долгосрочную ценность, показав, почему это хорошее решение проблемы, и сделало бы его более полезным для будущих читателей с другими подобными вопросами. Пожалуйста, отредактируйте свой ответ, чтобы добавить некоторые пояснения, включая сделанные вами предположения. - person Maximilian Peters; 13.04.2018
comment
Мне интересно, поддерживает ли это IE, поскольку Array.from этого не делает. Время найти машину с IE. Теперь я действительно запутался, потому что смог использовать Array.from в IE10 и IE11:\. Этот метод работает в IE10+11, но Array.from меня не успокаивает, когда вся документация говорит об обратном. - person CTS_AE; 12.07.2018
comment
Array.from у меня не работает в IE11 Объект не поддерживает свойство или метод 'from' - person Fus Ro Dah; 09.08.2018
comment
Спасибо, это сработало для меня на старой реализации JavaScript - person Vic Seedoubleyew; 05.05.2019
comment
Array.from также возвращает поверхностную копию. Поэтому я не понимаю, как вы заключаете, что он работает быстрее, чем Array#slice. - person Robert; 28.06.2020
comment
@Robert, спасибо за ваш комментарий, я обновил свой ответ. - person Serge Seletskyy; 28.06.2020

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

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

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

person goweon    schedule 16.04.2018

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

// 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.

person panepeter    schedule 23.01.2020
comment
небольшое предупреждение, теперь nodeList.filter предоставит вам массив вместо списка узлов. не должно быть проблемой, но легко забыть ^^ - person hanshenrik; 21.11.2020

Фильтровать или сопоставлять нодлисты в ES6

Я вышел из этой простой функции. @see https://developer.mozilla.org/fr/docs/Web/API/NodeList/entries#exemple

function filterNodeList(NodeList, callback) {
if (!typeof callback === "function") callback = (i) => i; // Any have better idear?

const Result = document.createElement("div");
//# No need to filter empty NodeList
if (Node.length === 0) return Node;

for (let i = 0; i < Node.length; i++) {
  if (callback(Node.item(i))) Result.appendChild(Node.item(i));
}

return Result.childNodes;}

Я хочу узнать больше :›

person FATCHOLA    schedule 28.07.2021
comment
Чтобы скопировать элементы в DOM, вы можете клонировать их и удалить ссылки Result.appendChild(NodeList.item(i).cloneNode). Далее, прежде чем вы начнете работать над ними, вам просто нужно вернуться и сказать, dom, дайте мне этот тип узла с этим атрибутом :: Важно! Узел === NodeList.... - person FATCHOLA; 29.07.2021