Lọc hoặc lập bản đồ danh sách nút trong ES6


87

Cách hiệu quả nhất để lọc hoặc lập bản đồ một danh sách nút trong ES6 là gì?

Dựa trên các bài đọc của tôi, tôi sẽ sử dụng một trong các tùy chọn sau:

[...nodelist].filter

hoặc là

Array.from(nodelist).filter

Bạn muốn giới thiệu cái nào? Và có những cách nào tốt hơn, chẳng hạn như không liên quan đến các mảng?


2
Về cơ bản, cả hai phương pháp đều làm điều tương tự. Nó bạn đang sử dụng babel, sau đó [...coll]sẽ chỉ đơn giản gọi Array.from(coll)cho bất kỳ thứ gì không phải là Array.
Leonid Beschastny

FWIW, ...cú pháp có thể không được hỗ trợ bởi các IDE cũ hơn trong khi Array.from()chỉ là một phương thức thông thường.
Marat Tanalin

Câu trả lời:


126
  • [...nodelist] sẽ tạo một mảng trong số một đối tượng nếu đối tượng có thể lặp lại.
  • Array.from(nodelist)sẽ tạo một mảng từ một đối tượng nếu đối tượng có thể lặp lại hoặc nếu đối tượng giống như mảng ( .lengthđạo cụ có và số)

Hai ví dụ của bạn sẽ giống hệt nhau nếu NodeList.prototype[Symbol.iterator]tồn tại, vì cả hai trường hợp đều bao gồm các tệp lặp lại. NodeListTuy nhiên, nếu môi trường của bạn chưa được cấu hình để có thể lặp lại, ví dụ đầu tiên của bạn sẽ thất bại và ví dụ thứ hai sẽ thành công. Babelhiện không xử lý đúng trường hợp này .

Vì vậy, nếu của bạn NodeListcó thể lặp lại, nó thực sự phụ thuộc vào bạn mà bạn sử dụng. Tôi có thể sẽ chọn theo từng trường hợp cụ thể. Một lợi ích của Array.fromnó là nó cần đối số thứ hai của một hàm ánh xạ, trong khi đối số thứ nhất [...iterable].map(item => item)sẽ phải tạo một mảng tạm thời, Array.from(iterable, item => item)thì không. Tuy nhiên, nếu bạn không lập bản đồ danh sách, điều đó không thành vấn đề.


17

TL; DR;

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

Phương thức slice () trả về một mảng. Mảng được trả về đó là một bản sao cạn của bộ sưu tập (NodeList) Vì vậy, nó hoạt động nhanh hơn Array.from () Vì vậy, nó hoạt động nhanh như Array.from ()

Các phần tử của tập hợp ban đầu được sao chép vào mảng trả về như sau:

  • Đối với tham chiếu đối tượng (và không phải đối tượng thực), lát sao chép các tham chiếu đối tượng vào mảng mới. Cả mảng ban đầu và mảng mới đều tham chiếu đến cùng một đối tượng. Nếu một đối tượng được tham chiếu thay đổi, các thay đổi sẽ hiển thị cho cả mảng mới và mảng ban đầu.
  • Đối với chuỗi, số và boolean (không phải đối tượng String, Number và Boolean), lát cắt sao chép các giá trị vào mảng mới. Các thay đổi đối với chuỗi, số hoặc boolean trong một mảng không ảnh hưởng đến mảng khác.

Giải thích ngắn gọn về các lập luận

Array.prototype.slice (beginIndex, endIndex)

  • lấy args tùy chọn beginIndex và endIndex. Nếu chúng không được cung cấp, các lát cắt sử dụng beginIndex == 0, do đó nó trích xuất tất cả các mục từ bộ sưu tập

Array.prototype.slice.call (không gian tên, beginIndex, endIndex)

  • lấy một đối tượng làm đối số đầu tiên. Nếu chúng ta sử dụng một bộ sưu tập như một đối tượng, nghĩa đen là chúng ta gọi phương thức lát cắt trực tiếp từ không gian tên đối tượng đó.slice ()

2
Cảm ơn bạn về đoạn mã này, đoạn mã này có thể cung cấp một số trợ giúp hạn chế, tức thì. Một lời giải thích phù hợp sẽ cải thiện đáng kể giá trị lâu dài của nó bằng cách chỉ ra lý do tại sao đây là một giải pháp tốt cho vấn đề và sẽ giúp nó hữu ích hơn cho những người đọc trong tương lai với những câu hỏi tương tự khác. Vui lòng chỉnh sửa câu trả lời của bạn để thêm một số giải thích, bao gồm cả những giả định bạn đã đưa ra.
Maximilian Peters

Tôi tự hỏi nếu điều này có hỗ trợ IE kể từ khi Array.fromkhông. Đã đến lúc tìm một máy IE. Bây giờ tôi thực sự bối rối vì tôi đã có thể sử dụng Array.from trong IE10 và IE11: \. Phương pháp này hoạt động trong IE10 + 11 nhưng tôi không thấy Array.from hoạt động khi tất cả các tài liệu hướng dẫn khác.
CTS_AE

Array.fromkhông làm việc cho tôi trong IE11 Object không hỗ trợ tài sản hoặc phương pháp 'từ'
Fus Ro Dah

Cảm ơn, điều này đã làm việc cho tôi trên một triển khai JavaScript cũ
Vic Seedoubleyew

1
Array.fromcũng trả về một bản sao cạn. Vì vậy, tôi không thấy làm thế nào bạn kết luận rằng nó hoạt động nhanh hơn Array#slice.
Robert

9

Tôi đã tìm thấy một tham chiếu sử dụng maptrực tiếp trên NodeList bằng cách

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

Tôi chưa thử nghiệm nó, nhưng có vẻ hợp lý rằng điều này sẽ nhanh hơn vì nó sẽ truy cập trực tiếp vào NodeList.


2

Còn cái này thì sao:

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

Đó là cách tiếp cận tương tự như đã đề cập trong tài liệu MDN cho NodeList.forEach (trong 'Polyfill'), nó hoạt động cho IE11 , Edge, Chrome và FF.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.