Фільтруйте або відображайте ноделісти в ES6


87

Який найефективніший спосіб фільтрувати або скласти карту вузлів у ES6?

Виходячи зі своїх показань, я скористався одним із таких варіантів:

[...nodelist].filter

або

Array.from(nodelist).filter

Який би ви порадили? І чи є кращі способи, наприклад, без залучення масивів?


2
В основному обидва методи роблять одне і те ж. Це ви використовуєте babel, тоді [...coll]просто попросите Array.from(coll)про все, що не є Array.
— Леонід Бесчастний

FWIW, ...синтаксис може не підтримуватися старими середовищами IDE, хоча Array.from()це звичайний метод.
— Marat Tanalin

Відповіді:


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 безпосередньо з цього простору імен об'єкта.

2
Дякуємо за цей фрагмент коду, який може надати обмежену негайну допомогу. Правильне пояснення значно покращило б його довгострокове значення, показавши, чому це хороше рішення проблеми, і зробило б його більш корисним для майбутніх читачів з іншими подібними питаннями. Будь ласка, відредагуйте свою відповідь, щоб додати пояснення, включаючи припущення, які ви зробили.
— Максиміліан Пітерс

Мені цікаво, чи підтримує це підтримку IE, оскільки Array.fromнемає. Час знайти машину IE. Зараз я справді заплутався, бо зміг використовувати Array.from в IE10 та IE11: \. Цей метод працює в IE10 + 11, але Array.from мене не полегшує, коли вся документація говорить про інше.
— CTS_AE

Array.fromне працює для мене в IE11 Об'єкт не підтримує властивість або метод 'from'
— Fus Ro Dah,

Дякую, це спрацювало для мене над старою реалізацією JavaScript
— Vic Seedoubleyew

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 (у розділі «Поліфіл»), він працює для IE11 , Edge, Chrome та FF.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.