Terinspirasi dengan menulis jawaban ini, saya akhirnya memperluas dan menulis posting blog yang membahas ini dengan cermat. Saya sarankan untuk memeriksanya jika Anda ingin mengembangkan pemahaman yang lebih dalam tentang bagaimana memikirkan masalah ini - saya mencoba menjelaskannya sepotong demi sepotong, dan juga memberikan perbandingan JSperf di akhir, membahas pertimbangan kecepatan.
Artinya, tl; dr adalah ini: Untuk mencapai apa yang Anda minta (pemfilteran dan pemetaan dalam satu panggilan fungsi), Anda akan menggunakanArray.reduce()
.
Namun, pendekatan 2 yang lebih mudah dibaca dan (kurang penting) biasanya secara signifikan lebih cepat 2 adalah dengan menggunakan filter dan peta yang dirangkai bersama:
[1,2,3].filter(num => num > 2).map(num => num * 2)
Berikut ini adalah penjelasan tentang cara Array.reduce()
kerja, dan bagaimana hal itu dapat digunakan untuk menyelesaikan filter dan memetakan dalam satu iterasi. Sekali lagi, jika ini terlalu padat, saya sangat menyarankan untuk melihat posting blog yang ditautkan di atas, yang merupakan pengantar yang jauh lebih ramah dengan contoh dan perkembangan yang jelas.
Anda memberikan pengurangan argumen yang merupakan fungsi (biasanya anonim).
Fungsi anonim itu mengambil dua parameter - satu (seperti fungsi anonim yang diteruskan ke map / filter / forEach) adalah iterasi yang akan dioperasikan. Ada argumen lain untuk fungsi anonim yang diteruskan untuk mengurangi, bagaimanapun, bahwa fungsi tersebut tidak menerima, dan itu adalah nilai yang akan diteruskan di antara pemanggilan fungsi, yang sering disebut sebagai memo .
Perhatikan bahwa sementara Array.filter () hanya mengambil satu argumen (fungsi), Array.reduce () juga membutuhkan argumen kedua yang penting (meskipun opsional): nilai awal untuk 'memo' yang akan diteruskan ke fungsi anonim itu sebagai argumen pertama, dan selanjutnya dapat dimutasi dan diteruskan di antara pemanggilan fungsi. (Jika tidak diberikan, maka 'memo' dalam pemanggilan fungsi anonim pertama secara default akan menjadi iterasi pertama, dan argumen 'iteratee' sebenarnya akan menjadi nilai kedua dalam larik)
Dalam kasus kami, kami akan mengirimkan array kosong untuk memulai, dan kemudian memilih apakah akan menyuntikkan iteratee kami ke dalam array kami atau tidak berdasarkan fungsi kami - ini adalah proses pemfilteran.
Akhirnya, kita akan mengembalikan 'array in progress' kita pada setiap pemanggilan fungsi anonim, dan reduce akan mengambil nilai kembali itu dan meneruskannya sebagai argumen (disebut memo) ke pemanggilan fungsi berikutnya.
Hal ini memungkinkan filter dan peta terjadi dalam satu iterasi, mengurangi setengah dari jumlah iterasi yang diperlukan - hanya melakukan pekerjaan dua kali lebih banyak setiap iterasi, jadi tidak ada yang benar-benar disimpan selain panggilan fungsi, yang tidak terlalu mahal dalam javascript .
Untuk penjelasan yang lebih lengkap, lihat dokumen MDN (atau posting saya yang direferensikan di awal jawaban ini).
Contoh dasar panggilan Reduce:
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)
versi yang lebih ringkas:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
Perhatikan bahwa iterasi pertama tidak lebih besar dari satu, sehingga difilter. Perhatikan juga initialMemo, yang diberi nama hanya untuk memperjelas keberadaannya dan menarik perhatian padanya. Sekali lagi, ini diteruskan sebagai 'memo' ke pemanggilan fungsi anonim pertama, dan kemudian nilai yang dikembalikan dari fungsi anonim diteruskan sebagai argumen 'memo' ke fungsi berikutnya.
Contoh lain dari kasus penggunaan klasik untuk memo akan mengembalikan angka terkecil atau terbesar dalam sebuah array. Contoh:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
Contoh bagaimana menulis fungsi reduce Anda sendiri (ini sering membantu memahami fungsi seperti ini, saya temukan):
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;
}
Implementasi sebenarnya memungkinkan akses ke hal-hal seperti indeks, misalnya, tetapi saya harap ini membantu Anda mendapatkan gambaran yang tidak rumit tentang intinya.