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

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;
}

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);

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);
}

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);
});

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.


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


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) ;


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
  });
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.