Tôi trình bày cách sử dụng .indexOf
và .splice
để xóa một mục khỏi mảng. Sau đó, tôi so sánh hiệu suất với vòng lặp for
và phương pháp .filter
Ảnh của Jackson Simmer trên Bapt
A câu hỏi thường gặp trong JavaScript là cách nhanh nhất để xóa một giá trị khỏi một mảng bằng các phương thức Javascript tích hợp [vanilla JS].
Nói cách khác, cách nhanh nhất để sửa đổi mảng không còn bao gồm một giá trị cụ thể
Bài viết này kiểm tra hiệu suất của 4 phương pháp khác nhau để xóa một mục cụ thể khỏi một mảng trong JavaScript
Xóa một mục khỏi Mảng
Một cách để giải quyết vấn đề này là sử dụng Array.prototype.indexOf[]
để tìm chỉ mục của giá trị, sau đó sử dụng Array.prototype.splice[]
để xóa mục đó
Lưu ý rằng .indexOf
trả về -1 nếu không tìm thấy chỉ mục, nhưng .splice
diễn giải chỉ mục -1 là mục cuối cùng trong mảng, giống như .indexOf
2
Đoạn mã sau sử dụng toán tử dấu chấm hỏi .indexOf
3 là tương đương
Bạn cũng có thể viết một lớp lót nếu bạn thực sự không bận tâm đến hiệu suất của việc tìm kiếm toàn bộ mảng hai lần nếu giá trị được tìm thấy
Tất cả các phương thức này chỉ xóa phiên bản đầu tiên của giá trị đã cho
Tôi sẽ thảo luận về các tùy chọn để xóa tất cả các mục phù hợp sau trong bài viết này
Còn vòng lặp for
thì sao?
A tùy chọn hoàn toàn tốt để xóa một mục khỏi mảng là sử dụng vòng lặp for
, mặc dù mã của bạn có thể khó đọc hơn.
Để làm cho nó tương đương với việc sử dụng .indexOf
và chỉ xóa phiên bản đầu tiên, tôi đã sử dụng một biến để theo dõi xem giá trị đã bị xóa hay chưa
Sau đây sẽ loại bỏ tất cả các phiên bản bằng cách sử dụng .indexOf
và .splice
Và phần sau đây sẽ xóa tất cả các phiên bản bằng vòng lặp for
Cái nào nhanh hơn?
P thử nghiệm hiệu suất bằng cách sử dụng các trường hợp thử nghiệm jsPerf này cho thấy sự khác biệt lớn giữa hai phương pháp loại bỏ một mục khỏi một mảng.
Sử dụng vòng lặp .splice
60 xuất hiện 2. Nhanh gấp 5 lần so với .indexOf
và .splice
Sự khác biệt này được phóng đại khi loại bỏ tất cả các phiên bản của giá trị phù hợp mà tôi đã thử nghiệm trong các trường hợp thử nghiệm jsPerf này
Như bạn có thể thấy, vòng lặp .splice
60 xuất hiện nhanh hơn gấp 5 lần so với vòng lặp .splice
64 sử dụng .indexOf
và .splice
theo cách thực sự kém hiệu quả
Nhưng những kết quả này là sai lệch — bởi vì bộ xử lý vẫn đang xử lý 4000 thao tác mỗi mili giây [4.000.000 thao tác/giây]
Như bạn sẽ thấy sau này, .indexOf
và .splice
thực sự có hiệu suất tốt hơn vòng lặp for
khi xử lý các mảng lớn gồm 10.000 mục
Còn về .filter
thì sao?
Nó là một điểm hợp lý để đề cập đến phương thức .filter
1 tích hợp, một trong những công cụ lập trình chức năng của JavaScript.
Dưới đây là một ví dụ về việc xóa tất cả các mục khỏi một mảng bằng cách sử dụng .filter
, trả về một mảng đã lọc gồm các giá trị khớp với điều kiện đã cho
Về mặt tích cực, bộ lọc dẫn đến ít mã hơn nhiều. Nhưng nó nhanh như thế nào?
Trong các trường hợp thử nghiệm jsPerf này, tôi đã so sánh .filter
với vòng lặp .filter
4 siêu chậm bằng cách sử dụng .indexOf
và .splice
và vòng lặp for
siêu nhanh
Như bạn có thể thấy, .filter
8 là một lựa chọn tốt — vòng lặp for
nhanh hơn một chút, nhưng .filter
8 vẫn ổn để loại bỏ tất cả các giá trị phù hợp khỏi một mảng
Cái nào nhanh nhất trong một mảng lớn?
Tất nhiên , dữ liệu trên kiểm tra các mảng nhỏ — và trình duyệt của tôi đang xử lý 4 triệu vòng lặp .filter
4 mỗi giây. Nhiều tốc độ.
Điều gì sẽ xảy ra nếu chúng ta đang làm việc với một mảng lớn hơn, chẳng hạn như 10.000 mục?
Trong mảng 10.000 mục mà mục tiêu [số 5.000] chỉ được tìm thấy một lần, vòng lặp .filter
4 với .indexOf
và .splice
thực sự thắng
Đối với trường hợp sử dụng này, .filter
là một kẻ thua cuộc lớn, vì vòng lặp for
nhanh hơn khoảng 5 lần. Nhưng .indexOf
và .splice
nhanh gấp đôi so với vòng lặp for
So sánh điều đó với một mảng 10.000 mục trong đó mục tiêu [số 5.000] được tìm thấy như mọi mục khác trong mảng. Kết quả hoàn toàn giống nhau
Suy nghĩ về ý nghĩa của những con số đó,. bộ lọc chỉ lấy 0. 25 mili giây để xử lý mảng 10.000 mục — vẫn khá nhanh
Thông điệp mang về nhà là đừng tham gia vào việc tối ưu hóa sớm
Sử dụng mã dễ đọc nhất có thể, sau đó chỉ tối ưu hóa nếu cần
Làm thế nào để tránh đột biến?
N lưu ý rằng .splice
0 sửa đổi mảng tại chỗ, điều này thường tốt cho hiệu suất nhưng bạn có thể gặp tác dụng phụ [lỗi].
Xin lưu ý rằng việc sửa đổi một đối tượng, còn được gọi là thay đổi đối tượng, đôi khi được coi là thực hành mã xấu, vì khả năng xảy ra tác dụng phụ
Thậm chí còn có một plugin ESLint [eslint-plugin-immutable] vô hiệu hóa hoàn toàn tất cả các đột biến đối tượng — một ý tưởng hay để ngăn ngừa lỗi
Nhưng làm cách nào bạn có thể xóa một mục khỏi mảng mà không làm thay đổi mảng ban đầu?
Phương thức vòng lặp for
đã tránh được đột biến, bởi vì bạn đang .splice
2 các mục vào một mảng mới. Đây vốn dĩ là một bản sao nông của mảng
Nếu bạn cần tạo một bản sao sâu, do các đối tượng hoặc mảng lồng nhau bên trong một mảng, thì hãy xem bài viết của tôi về sao chép sâu mảng trong JavaScript
Cách sao chép sâu các đối tượng và mảng trong JavaScript
Các phương pháp sao chép đối tượng hoặc mảng thông thường chỉ tạo ra một bản sao nông, vì vậy các tham chiếu được lồng sâu là một vấn đề…
vừa phải. com
Sự kết luận
N Bây giờ bạn đã hiểu cách kết hợp .indexOf
và .splice
để xóa mục nhập khỏi mảng JavaScript, do đó thay đổi mảng tại chỗ.
Để tránh thay đổi mảng, hãy tạo một bản sao nông hoặc sử dụng vòng lặp for
Vòng lặp for
cũng là một lựa chọn tuyệt vời nếu bạn cần xóa mọi giá trị phù hợp khỏi một mảng— hoặc chỉ sử dụng .filter
để lọc ra các mục phù hợp
Mặc dù kết hợp .indexOf
và .splice
chậm hơn so với sử dụng vòng lặp for
cho các mảng nhỏ, nhưng hiệu suất sẽ khác nhau đối với các mảng lớn hơn
Khuyến nghị của tôi là sử dụng các phiên bản dễ đọc nhất trong mã của bạn
.indexOf
và.splice
để chỉ xóa phiên bản đầu tiên của một giá trị.filter
để xóa mọi phiên bản của một giá trị khỏi một mảng
Các phương thức đó sẽ tự ghi lại nhiều tài liệu hơn so với vòng lặp for
, nơi bạn sẽ cần viết nhận xét giải thích mã của mình
Để có hiệu suất tốt nhất khi loại bỏ các mục khỏi mảng lớn, hãy xem xét .indexOf
và .splice
, vì phương pháp đó có thể khá nhanh