กรองหรือแมป nodelists ใน ES6


90

วิธีใดที่มีประสิทธิภาพที่สุดในการกรองหรือแมป nodelist ใน ES6

จากการอ่านของฉันฉันจะใช้หนึ่งในตัวเลือกต่อไปนี้:

[...nodelist].filter

หรือ

Array.from(nodelist).filter

ท่านใดจะแนะนำ และมีวิธีที่ดีกว่าเช่นโดยไม่ต้องเกี่ยวข้องกับอาร์เรย์หรือไม่?


2
โดยทั่วไปแล้วทั้งสองวิธีจะทำสิ่งเดียวกัน มันคุณกำลังใช้babelแล้ว[...coll]ก็จะเรียกสำหรับสิ่งที่ไม่ได้เป็นArray.from(coll) Array
Leonid Beschastny

FWIW ...ไวยากรณ์อาจไม่รองรับโดย IDE รุ่นเก่าในขณะที่Array.from()เป็นเพียงวิธีการทั่วไป
Marat Tanalin

คำตอบ:


131
  • [...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)

  • ใช้ args ที่เป็นทางเลือก beginIndex และ endIndex หากไม่ได้จัดเตรียมชิ้นส่วนให้ใช้ startIndex == 0 ดังนั้นจะแยกรายการทั้งหมดออกจากคอลเลกชัน

Array.prototype.slice.call (เนมสเปซ, beginIndex, endIndex)

  • ใช้วัตถุเป็นอาร์กิวเมนต์แรก ถ้าเราใช้คอลเลกชันเป็นวัตถุหมายความว่าเราเรียกเมธอด slice โดยตรงจากวัตถุนั้นnamespace.slice ()

2
ขอบคุณสำหรับข้อมูลโค้ดนี้ซึ่งอาจให้ความช่วยเหลือเฉพาะบางอย่างได้ทันที คำอธิบายที่เหมาะสมจะช่วยเพิ่มมูลค่าในระยะยาวได้อย่างมากโดยแสดงให้เห็นว่าเหตุใดจึงเป็นวิธีแก้ปัญหาที่ดีและจะทำให้มีประโยชน์มากขึ้นสำหรับผู้อ่านในอนาคตด้วยคำถามอื่น ๆ ที่คล้ายคลึงกัน โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายรวมถึงสมมติฐานที่คุณตั้งขึ้น
Maximilian Peters

ฉันสงสัยว่าสิ่งนี้มีการรองรับ IE Array.fromหรือไม่ ได้เวลาหาเครื่อง IE ตอนนี้ฉันสับสนมากเพราะฉันสามารถใช้ Array.from ใน IE10 และ IE11: \. วิธีนี้ใช้งานได้ใน IE10 + 11 แต่ฉันไม่ได้รับการผ่อนคลายโดย Array.from ทำงานเมื่อเอกสารทั้งหมดระบุเป็นอย่างอื่น
CTS_AE

Array.fromไม่ทำงานสำหรับฉันใน IE11 Object ไม่รองรับคุณสมบัติหรือวิธีการ 'from'
Fus Ro Dah

ขอบคุณสิ่งนี้ใช้ได้ผลสำหรับฉันในการใช้งาน JavaScript แบบเก่า
Vic Seedoubleyew

1
Array.fromยังส่งคืนสำเนาตื้น ดังนั้นผมจึงไม่เห็นว่าคุณสรุปArray#sliceว่ามันทำงานได้เร็วกว่า
Robert

9

ฉันพบข้อมูลอ้างอิงที่ใช้mapโดยตรงบน NodeList โดย

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

ฉันยังไม่ได้ทดสอบ แต่ดูเหมือนจะเป็นไปได้ว่าสิ่งนี้จะเร็วกว่าเพราะควรเข้าถึง NodeList โดยตรง


4

แล้วสิ่งนี้ล่ะ:

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


คำเตือนเล็กน้อยตอนนี้ nodeList.filter จะให้อาร์เรย์แทนรายการโหนด ไม่น่าจะเป็นปัญหา แต่ลืมง่าย ^^
hanshenrik
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.