Jak przekazać dodatkowy parametr do funkcji wywołania zwrotnego w metodzie .filter () języka JavaScript?

105

Chcę porównać każdy ciąg w tablicy z podanym ciągiem. Moja obecna realizacja to:

function startsWith(element) {
    return element.indexOf(wordToCompare) === 0;
}
addressBook.filter(startsWith);

Ta prosta funkcja działa, ale tylko dlatego, że w tej chwili wordToCompare jest ustawiana jako zmienna globalna, ale oczywiście chcę tego uniknąć i przekazać to jako parametr. Mój problem polega na tym, że nie jestem pewien, jak zdefiniować startedWith (), więc akceptuje jeden dodatkowy parametr, ponieważ tak naprawdę nie rozumiem, w jaki sposób są przekazywane domyślne parametry, które przyjmuje. Wypróbowałem wszystkie możliwe sposoby i żaden z nich nie działa.

Gdybyś mógł również wyjaśnić, jak działają parametry przekazane do `` wbudowanych '' funkcji zwrotnych (przepraszam, nie znam lepszego terminu na te), byłoby świetnie

agente_secreto
źródło

Odpowiedzi:

153

Dokonaj startsWithzaakceptować słowo porównać przed i powrócić do funkcji , które zostaną następnie wykorzystane jako funkcja filter / callback:

function startsWith(wordToCompare) {
    return function(element) {
        return element.indexOf(wordToCompare) === 0;
    }
}

addressBook.filter(startsWith(wordToCompare));

Inną opcją byłoby użycie Function.prototype.bind [MDN] (dostępne tylko w przeglądarce obsługującej ECMAScript 5, podążaj za linkiem do podkładki dla starszych przeglądarek) i „napraw” pierwszy argument:

function startsWith(wordToCompare, element) {
    return element.indexOf(wordToCompare) === 0;
}

addressBook.filter(startsWith.bind(this, wordToCompare));

Naprawdę nie rozumiem, w jaki sposób przekazywane są domyślne parametry

Nie ma w tym nic specjalnego. W pewnym momencie filterpo prostu wywołuje funkcję zwrotną i przekazuje bieżący element tablicy. Jest to więc funkcja wywołująca inną funkcję, w tym przypadku wywołanie zwrotne, które przekazujesz jako argument.

Oto przykład podobnej funkcji:

function filter(array, callback) {
    var result = [];
    for(var i = 0, l = array.length; i < l; i++) {
        if(callback(array[i])) {  // here callback is called with the current element
            result.push(array[i]);
        }
    }
    return result;
}
Felix Kling
źródło
1
Ok, teraz rozumiem. Próbowałem przekazać parametry bezpośrednio do funkcji zwrotnej ... Naprawdę muszę popracować nad moim JavaScriptem. Dziękuję Felix, twoja odpowiedź jest bardzo pomocna
agente_secreto
A co z przekazywaniem dodatkowych argumentów? Próbowałem przekazać szereg argumentów, ale wydaje się, że to się nie udaje
geoteoria
@geotheory: co z nimi? przekazujesz wiele argumentów, jak do każdej innej funkcji.
Felix Kling
bind (this) po nazwie funkcji wraz z łańcuchem filter () pomogło mi użyć .this wewnątrz funkcji. Dzięki.
Sagar Khatri
109

Drugi parametr filtru ustawi to w wywołaniu zwrotnym.

arr.filter(callback[, thisArg])

Możesz więc zrobić coś takiego:

function startsWith(element) {
    return element.indexOf(this) === 0;
}
addressBook.filter(startsWith, wordToCompare);
Jeff
źródło
7
Uważam, że to najlepsza odpowiedź.
Jeaf Gilbert,
więc teraz nowa tablica zostanie przypisana do obiektu wordToCompare, prawda? Jak można później uzyskać dostęp do nowej tablicy za pomocą obiektu wordToCompare?
Badhon Jain
najlepsza odpowiedź. działa idealnie zarówno w przypadku filtrowania, jak i znajdowania. I jest zgodne z dokumentacją WC3 dla obu: thisValue - Optional. Wartość, która ma zostać przekazana do funkcji, która ma być używana jako jej wartość „ta”. Jeśli ten parametr jest pusty, wartość „undefined” zostanie przekazana jako jego wartość „this”
richaa.
1
@TarekEldeeb po prostu podaj obiekt, który stworzyłeś{one: 'haha', two:'hoho'}
toddmo
2
To świetny przykład tego, jak mogą istnieć ogromne różnice między odpowiedziami co do złożoności i tego, jak skomplikowane mogą być, w porównaniu z tym, jak proste mogą być
toddmo
14

Dla tych, którzy szukają alternatywy dla ES6 z funkcjami strzałkowymi, możesz wykonać następujące czynności.

let startsWith = wordToCompare => (element, index, array) => {
  return element.indexOf(wordToCompare) === 0;
}

// where word would be your argument
let result = addressBook.filter(startsWith("word"));

Zaktualizowana wersja przy użyciu obejmuje :

const startsWith = wordToCompare => (element, index, array) => {
  return element.includes(wordToCompare);
}
jhamPac
źródło
Czy istnieje sposób przekazania innego parametru z elementu, indeksu i tablicy? Na przykład chcę przekazać zmienną X.
leandrotk
@leandrotk w tym przypadku „wordToCompare” to zmienna „X” do przekazania.
GetBackerZ
11
function startsWith(element, wordToCompare) {
    return element.indexOf(wordToCompare) === 0;
}

// ...
var word = "SOMETHING";

addressBook.filter(function(element){
    return startsWith(element, word);
});
James Montagne
źródło
4

Możesz użyć funkcji strzałek wewnątrz filtra, na przykład:

result = addressBook.filter(element => element.indexOf(wordToCompare) === 0);

Funkcje strzałek na MDN

Wyrażenie funkcji strzałkowej ma krótszą składnię w porównaniu z wyrażeniami funkcyjnymi i leksykalnie wiąże wartość this (nie wiąże swojej własnej this, arguments, super lub new.target). Funkcje strzałkowe są zawsze anonimowe. Te wyrażenia funkcyjne najlepiej nadają się do funkcji niebędących metodami i nie można ich używać jako konstruktorów.

oddRaven
źródło
Uwaga: nieobsługiwane w IE
Luis Lavieri
1

Dla każdego, kto zastanawia się, dlaczego ignoruje funkcję fat arrow [, thisArg], np. Dlaczego

["DOG", "CAT", "DOG"].filter(animal => animal === this, "DOG") zwroty []

Dzieje się tak dlatego, że thiswewnątrz tych strzałek funkcje są powiązane, gdy funkcja jest tworzona i są ustawiane na wartość thisw szerszym zakresie obejmującym, więc thisArgargument jest ignorowany. Poradziłem sobie z tym dość łatwo, deklarując nową zmienną w zakresie nadrzędnym:

let bestPet = "DOG"; ["DOG", "CAT", "DOG"].filter(animal => animal === bestPet); => ["DOG", "DOG"]

Oto link do dalszych lektur: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this

JKettler
źródło
0

na podstawie odpowiedzi oddRaven i https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

zrobiłem to w 2 inny sposób. 1) za pomocą sposobu funkcji. 2) przy użyciu metody inline.

//Here  is sample codes : 

var templateList   = [
{ name: "name1", index: 1, dimension: 1 }  ,
{ name: "name2", index: 2, dimension: 1 }  ,
{ name: "name3", index: 3, dimension: 2 }  ];


//Method 1) using function : 

function getDimension1(obj) {
                if (obj.dimension === 1) // This is hardcoded . 
                    return true;
                else return false;
            } 

var tl = templateList.filter(getDimension1); // it will return 2 results. 1st and 2nd objects. 
console.log(tl) ;

//Method 2) using inline way 
var tl3 = templateList.filter(element => element.index === 1 || element.dimension === 2  ); 
// it will return 1st and 3rd objects 
console.log(tl3) ;

Ashish
źródło
0

Istnieje łatwy sposób korzystania z funkcji filtra, dostępu do wszystkich parametrów i nie komplikowania go zbytnio.

O ile thisArg wywołania zwrotnego nie jest ustawione na inny filtr zakresu, nie tworzy własnego zakresu i możemy uzyskać dostęp do parametrów w bieżącym zakresie. Możemy ustawić „this”, aby zdefiniować inny zakres, aby w razie potrzeby uzyskać dostęp do innych wartości, ale domyślnie jest ustawiony na zakres, z którego jest wywoływany. Możesz zobaczyć, że jest to używane dla teleskopów Angular w tym stosie .

Korzystanie z indexOf jest sprzeczne z celem filtra i zwiększa obciążenie. Filtr już przechodzi przez tablicę, więc dlaczego musimy ponownie go iterować? Zamiast tego możemy uczynić z tego prostą czystą funkcję .

Oto scenariusz użycia w ramach metody klasy React, w którym stan ma tablicę o nazwie items , a za pomocą filtru możemy sprawdzić istniejący stan:

checkList = (item) => {  // we can access this param and globals within filter
  var result = this.state.filter(value => value === item); // returns array of matching items

  result.length ? return `${item} exists` : this.setState({
    items: items.push(item) // bad practice, but to keep it light
  });
}
Brązowy
źródło