Bu cevabı yazarak esinlenerek, daha sonra bunu ayrıntılı bir şekilde ele alan bir blog yazısı yazdım ve genişlettim. Bu sorun hakkında daha derin bir anlayış geliştirmek istiyorsanız, bunu kontrol etmenizi öneririm - bunu parça parça açıklamaya çalışıyorum ve sonunda hız hususlarının üzerinden geçerek bir JSperf karşılaştırması yapıyorum.
Bununla birlikte, tl; dr şudur: İstediğiniz şeyi başarmak için (bir işlev çağrısı içinde filtreleme ve haritalama) kullanırsınızArray.reduce()
.
Bununla birlikte, daha okunabilir ve (daha az önemli olarak) genellikle önemli ölçüde daha hızlı 2 yaklaşım, yalnızca filtre ve harita zincirinin birlikte kullanılmasıdır:
[1,2,3].filter(num => num > 2).map(num => num * 2)
Aşağıda, nasıl Array.reduce()
çalıştığı ve tek bir yinelemede filtreleme ve eşleme yapmak için nasıl kullanılabileceği açıklanmaktadır. Yine, eğer bu çok yoğunsa, yukarıda bağlantılı blog gönderisini görmenizi şiddetle tavsiye ederim, bu açık örnekler ve ilerlemeyle çok daha dostane bir giriş.
İndirgeme (genellikle anonim) bir işlev olan bir argüman verirsiniz.
Bu anonim işlev iki parametre alır - biri (map / filter / forEach'e aktarılan anonim işlevler gibi) üzerinde çalıştırılacak yineleme. Ancak, bu işlevlerin kabul etmediği ve genellikle not olarak adlandırılan işlev çağrıları arasında iletilecek değerin azaltılması için geçirilen anonim işlev için başka bir argüman daha vardır .
Array.filter () yalnızca bir bağımsız değişken (bir işlev) alırken, Array.reduce () öğesinin önemli (isteğe bağlı olsa da) ikinci bir bağımsız değişken aldığını unutmayın: 'memo' için, onun olarak ilk argüman ve daha sonra mutasyona uğratılabilir ve işlev çağrıları arasında aktarılabilir. (Sağlanmazsa, ilk anonim işlev çağrısındaki 'not' varsayılan olarak ilk yineleme olur ve 'yineleme' argümanı aslında dizideki ikinci değer olur)
Bizim durumumuzda, başlamak için boş bir dizi geçireceğiz ve ardından yinelememizi dizimize enjekte edip etmemeyi fonksiyonumuza göre seçeceğiz - bu filtreleme işlemidir.
Son olarak, her anonim işlev çağrısında 'devam eden dizimizi' döndüreceğiz ve azaltma bu dönüş değerini alacak ve bir sonraki işlev çağrısına bir argüman (memo olarak adlandırılır) olarak aktaracaktır.
Bu, filtre ve eşlemenin tek bir yinelemede gerçekleşmesine izin vererek gerekli yineleme sayımızı yarıya indirir - her yinelemede yalnızca iki kat daha fazla iş yapar, bu nedenle javascript'te çok pahalı olmayan işlev çağrıları dışında hiçbir şey gerçekten kaydedilmez .
Daha eksiksiz bir açıklama için MDN belgelerine (veya bu cevabın başında atıfta bulunulan gönderime) bakın.
Azalt çağrısının temel örneği:
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)
daha kısa ve öz sürüm:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
İlk yinelemenin birden büyük olmadığına ve dolayısıyla filtrelendiğine dikkat edin. Ayrıca, varlığını netleştirmek ve dikkat çekmek için adlandırılan initialMemo'ya da dikkat edin. Bir kez daha, ilk anonim işlev çağrısına "not" olarak aktarılır ve ardından anonim işlevin döndürülen değeri, sonraki işleve "not" argümanı olarak aktarılır.
Not için klasik kullanım durumunun başka bir örneği, bir dizideki en küçük veya en büyük sayıyı döndürmektir. Misal:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
Kendi azaltma işlevinizi nasıl yazacağınıza dair bir örnek (bu genellikle bunun gibi işlevleri anlamaya yardımcı olur, buluyorum):
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;
}
Gerçek uygulama, örneğin dizin gibi şeylere erişime izin verir, ancak umarım bu, ana fikri için karmaşık olmayan bir his edinmenize yardımcı olur.