Lấy cảm hứng từ việc viết câu trả lời này, cuối cùng tôi đã mở rộng và viết một bài blog về vấn đề này một cách chi tiết. Tôi khuyên bạn nên kiểm tra điều đó nếu bạn muốn hiểu sâu hơn về cách suy nghĩ về vấn đề này - Tôi cố gắng giải thích từng phần một và cũng đưa ra so sánh JSperf ở cuối, xem xét tốc độ.
Điều đó nói rằng, tl; dr là thế này: Để thực hiện những gì bạn đang yêu cầu (lọc và ánh xạ trong một lệnh gọi hàm), bạn sẽ sử dụngArray.reduce()
.
Tuy nhiên, cách tiếp cận 2 dễ đọc hơn và (ít quan trọng hơn) thường nhanh hơn đáng kể là chỉ sử dụng bộ lọc và bản đồ được xâu chuỗi với nhau:
[1,2,3].filter(num => num > 2).map(num => num * 2)
Sau đây là mô tả về cách Array.reduce()
hoạt động và cách nó có thể được sử dụng để thực hiện bộ lọc và ánh xạ trong một lần lặp. Một lần nữa, nếu điều này quá cô đọng, tôi thực sự khuyên bạn nên xem bài đăng blog được liên kết ở trên, đây là phần giới thiệu thân thiện hơn nhiều với các ví dụ rõ ràng và tiến trình.
Bạn cung cấp một đối số là một hàm (thường ẩn danh).
Hàm ẩn danh đó nhận hai tham số - một (như các hàm ẩn danh được truyền vào map / filter / forEach) là hàm lặp sẽ được vận hành. Tuy nhiên, có một đối số khác cho hàm ẩn danh được truyền để giảm mà các hàm đó không chấp nhận và đó là giá trị sẽ được truyền giữa các lần gọi hàm, thường được gọi là bản ghi nhớ .
Lưu ý rằng trong khi Array.filter () chỉ nhận một đối số (một hàm), Array.reduce () cũng nhận một đối số thứ hai (mặc dù tùy chọn) quan trọng: một giá trị ban đầu cho 'bản ghi nhớ' sẽ được chuyển vào hàm ẩn danh đó dưới dạng đối số đầu tiên, và sau đó có thể được thay đổi và chuyển giữa các lệnh gọi hàm. (Nếu nó không được cung cấp, thì 'bản ghi nhớ' trong lệnh gọi hàm ẩn danh đầu tiên theo mặc định sẽ là lần lặp đầu tiên và đối số 'lặp lại' sẽ thực sự là giá trị thứ hai trong mảng)
Trong trường hợp của chúng tôi, chúng tôi sẽ truyền vào một mảng trống để bắt đầu, và sau đó chọn có đưa tệp lặp vào mảng của chúng tôi hay không dựa trên chức năng của chúng tôi - đây là quá trình lọc.
Cuối cùng, chúng tôi sẽ trả về 'mảng đang xử lý' của chúng tôi trên mỗi lệnh gọi hàm ẩn danh và giảm sẽ nhận giá trị trả về đó và chuyển nó dưới dạng đối số (được gọi là bản ghi nhớ) cho lệnh gọi hàm tiếp theo của nó.
Điều này cho phép bộ lọc và ánh xạ xảy ra trong một lần lặp, giảm một nửa số lần lặp bắt buộc của chúng tôi - tuy nhiên, chỉ thực hiện gấp đôi công việc mỗi lần lặp, vì vậy không có gì thực sự được lưu ngoài các lệnh gọi hàm, điều này không quá đắt trong javascript .
Để có lời giải thích đầy đủ hơn, hãy tham khảo tài liệu MDN (hoặc bài đăng của tôi được tham chiếu ở đầu câu trả lời này).
Ví dụ cơ bản về lệnh gọi Rút gọn:
let array = [1,2,3];
const initialMemo = [];
array = array.reduce((memo, iteratee) => {
if (iteratee > 1) {
memo.push(iteratee * 2);
}
return memo;
}, initialMemo)
console.log(array)
phiên bản ngắn gọn hơn:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
Lưu ý rằng vòng lặp đầu tiên không lớn hơn một và vì vậy đã được lọc. Cũng lưu ý đến InitialMemo, được đặt tên chỉ để làm rõ sự tồn tại của nó và thu hút sự chú ý đến nó. Một lần nữa, nó được chuyển dưới dạng 'bản ghi nhớ' cho lệnh gọi hàm ẩn danh đầu tiên, và sau đó giá trị trả về của hàm ẩn danh được chuyển vào dưới dạng đối số 'bản ghi nhớ' cho hàm tiếp theo.
Một ví dụ khác về trường hợp sử dụng cổ điển cho bản ghi nhớ sẽ trả về số nhỏ nhất hoặc lớn nhất trong một mảng. Thí dụ:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
Một ví dụ về cách viết hàm giảm của riêng bạn (điều này thường giúp hiểu các hàm như thế này, tôi tìm thấy):
test_arr = [];
test_arr.my_reducer = function(reduceFunc, initialMemo) {
const initialMemoIsIndexZero = arguments.length < 2;
let memo = initialMemoIsIndexZero ? this[0] : initialMemo;
const initialIteratee = initialMemoIsIndexZero ? 1 : 0;
for (var i = initialIteratee; i < this.length; i++) {
memo = reduceFunc(memo, this[i]);
}
return memo;
}
Việc triển khai thực cho phép truy cập vào những thứ như chỉ mục, chẳng hạn, nhưng tôi hy vọng điều này sẽ giúp bạn có được cảm giác không phức tạp về ý chính của nó.