Javascript posiada wbudowaną metodę filter() służącą do przeszukiwania tablicy wartości w poszukiwaniu pasujących danych. Metoda filter może być wywołana tylko dla zmiennych typu array – a więc nie pozwala na użycie na zmiennych typu object. Co ciekawe, funkcja filter radzi sobie dobrze w przypadku, gdy mamy zmienną typu array w której znajdują się zmienne typu object.

Przykład użycia:

let products = [
    {
        "name" : "Lenovo T440p",
        'brand' : "Lenovo",
        "series" : "ThinkPad"
    },
    {
        "name" : "Lenovo Legion 5-15",
        'brand' : "Lenovo",
        "series" : "Legion"
    },
    {
        "name" : "Macbook Air M1",
        'brand' : "Apple",
        "series" : "M1 Series"
    }
];

let onlyLenovo = products.filter(searchLenovo);

function searchLenovo (product) {
    return product.brand == 'Lenovo';
}

console.log(onlyLenovo);
/* 
console:
0:
    brand: "Lenovo"
    name: "Lenovo T440p"
    series: "ThinkPad"
1:
    brand: "Lenovo"
    name: "Lenovo Legion 5-15"
    series: "Legion"
length: 2

*/

Powyżej została zdefiniowana tablica products (array) przechowująca dane o produktach. Produkty posiadają właściwości: name, brand, series.

Następnie, definiujemy zmienną onlyLenovo, zmienna ta będzie przechowywać wyniki funkcji filter(). Funkcja filter jest wywoływana na zmiennej products, ale nie będzie zmieniać, dodawać ani usuwać wartości tej zmiennej. Wyniki funkcji filter zostaną przypisane do zmiennej onlyLenovo.

Parametrem funkcji filter, jest funkcja searchLenovo, która jest zdefiniowana poniżej. Funkcja searchLenovo przechwytuje pojedynczy wiersz tablicy a następnie wykonuje zaprogramowane instrukcje. Funkcja ta jest wywoływana iteracyjnie, dla każdego wiersza tablicy products. W powyższym przykładzie, tablica products posiada 3 wiersze, więc funkcja searchLenovo zostanie wywołana 3 razy.

Funkcja searchLenovo powinna zwracać wartość Boolean (true lub false). Jeżeli funkcja zwróci true, wówczas wiersz spełniający warunek, zostanie przypisany do zmiennej onlyLenovo. W przypadku, gdy funkcja zwróci warto false, wiersz tablicy zostanie pomięty, przez co nie zostanie przypisany do tablicy.

Równie dobrze, możemy rozbudowac warunek wewnątrz funkcji filter().

function searchLaptopForWork (product) {
    return product.brand == 'Apple' || product.series == 'ThinkPad';
}

laptopForWork = products.filter(searchLaptopForWork);

console.log(laptopForWork);

/* 
console:
0:
    brand: "Lenovo"
    name: "Lenovo T440p"
    series: "ThinkPad"

1:
    brand: "Apple"
    name: "Macbook Air M1"
    series: "M1 Series"
length: 2
*/

Oba powyższe przykłady są statyczne – aby nadać trochę dynamiczności powyższych funkcji, powinniśmy zrezygnować z ustawiania warunków na sztywno.
Dlaczego to ważne? Bo programiści to leniwce 😉

Zaawansowany case study:

Użytkownikowi zostaje przedstawiona lista 100 produktów. Użytkownik chce móc filtrować produkty w różnych konfiguracjach. Chce móc filtrować przy użyciu brandów, nazw, cen lub/i popularności.

Rozwiązanie:

Korzystając z natywnej funkcji filter() pokazanej w poprzednim przykładzie, musielibyśmy stworzyć X funkcji, dla każdej możliwej kombinacji zapytań.
Taki problem rozwiązałem przy użyciu Object.defineProperty(); tworząc własną funkcję filtrującą.

Object.defineProperty(Array.prototype, 'flexFilter', {
    enumerable: false,
    value: function(searchValues) {
        let matches = [];
        let isMatch = true;
        let thisArray = this;
        for (const arrayKey in thisArray) {
            let arrayValue = thisArray[arrayKey];
            isMatch = true;
            for (const searchKey in searchValues) {
                let searchValue = searchValues[searchKey]; 
                // array of filter values
                if ( searchValue.length ) {
                    if ( ! searchValue.includes(arrayValue[searchKey]) ) {
                        isMatch = false;
                    }
                }
            }
            if ( isMatch ) {
                matches.push(arrayValue);
            }
        }

        return matches;
    }
});

var productMaching = Products.flexFilter(selectedFilters);