Фільтруйте або відображайте ноделісти в 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.