Come faccio a passare un parametro aggiuntivo alla funzione di callback nel metodo Javascript .filter ()?


104

Voglio confrontare ogni stringa in un array con una data stringa. La mia attuale implementazione è:

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

Questa semplice funzione funziona, ma solo perché in questo momento wordToCompare viene impostato come variabile globale, ma ovviamente voglio evitarlo e passarlo come parametro. Il mio problema è che non sono sicuro di come definire startsWith () quindi accetta un parametro extra, perché non capisco davvero come vengono passati i parametri predefiniti che richiede. Ho provato tutti i diversi modi in cui riesco a pensare e nessuno di loro funziona.

Se potessi anche spiegare come funzionano i parametri passati alle funzioni di callback 'incorporate' (mi dispiace, non conosco un termine migliore per queste), sarebbe fantastico

Risposte:


152

Fai startsWithaccettare la parola con cui confrontare e restituisci una funzione che verrà quindi utilizzata come funzione di filtro / callback:

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

addressBook.filter(startsWith(wordToCompare));

Un'altra opzione potrebbe essere quella di utilizzare Function.prototype.bind [MDN] (disponibile solo nei browser che supportano ECMAScript 5, seguire un collegamento per uno shim per i browser meno recenti) e "correggere" il primo argomento:

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

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

Non capisco davvero come vengono passati i parametri predefiniti necessari

Non c'è niente di speciale in questo. Ad un certo punto, filterchiama semplicemente il callback e passa l'elemento corrente dell'array. Quindi è una funzione che chiama un'altra funzione, in questo caso il callback che passi come argomento.

Ecco un esempio di una funzione simile:

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 ora capisco. Stavo cercando di passare i parametri direttamente alla funzione di callback ... Ho davvero bisogno di lavorare sul mio JavaScript. Grazie Felix, la tua risposta è molto utile
agente_secreto

Che ne dici di passare argomenti aggiuntivi? Ho provato a passare una serie di argomenti ma sembra fallire
geoteoria

@geotheory: che mi dici di loro? passi più argomenti come per qualsiasi altra funzione.
Felix Kling

bind (this) dopo il nome della funzione insieme al concatenamento di filter () mi ha aiutato a usare .questa funzione interna. Grazie.
Sagar Khatri

109

Il secondo parametro di filtro imposterà questo all'interno della richiamata.

arr.filter(callback[, thisArg])

Quindi potresti fare qualcosa come:

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

7
Ho trovato che questa è la risposta migliore.
Jeaf Gilbert

quindi ora il nuovo array verrà assegnato all'oggetto wordToCompare, giusto? Come si può accedere successivamente al nuovo array utilizzando l'oggetto wordToCompare?
Badhon Jain

migliore risposta. funziona perfettamente sia per il filtro che per la ricerca. Ed è secondo la documentazione WC3 per entrambi: thisValue - Facoltativo. Un valore da passare alla funzione da utilizzare come valore "this". Se questo parametro è vuoto, il valore "undefined" verrà passato come valore "this"
richaa

1
@TarekEldeeb passa semplicemente un oggetto che crei{one: 'haha', two:'hoho'}
toddmo

2
Questo è un ottimo esempio di come possono esserci grandi differenze tra le risposte sulla complessità e su quanto possono essere contorte rispetto a quanto possono essere semplici
Toddmo

13

Per coloro che cercano un'alternativa a ES6 utilizzando le funzioni delle frecce, è possibile eseguire le seguenti operazioni.

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

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

La versione aggiornata utilizzando include :

const startsWith = wordToCompare => (element, index, array) => {
  return element.includes(wordToCompare);
}

C'è un modo per passare un parametro diverso da element, index e array? Ad esempio, voglio passare una variabile X.
leandrotk

@leandrotk in questo caso "wordToCompare" è la variabile "X" da passare.
GetBackerZ

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

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

addressBook.filter(function(element){
    return startsWith(element, word);
});

4

Puoi usare la funzione freccia all'interno di un filtro, in questo modo:

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

Funzioni freccia su MDN

Un'espressione di funzione freccia ha una sintassi più breve rispetto alle espressioni di funzione e associa lessicalmente il valore this (non lega il proprio this, arguments, super o new.target). Le funzioni delle frecce sono sempre anonime. Queste espressioni di funzione sono più adatte per funzioni non di metodo e non possono essere utilizzate come costruttori.


Nota: non supportato su IE
Luis Lavieri

1

Per chiunque si chieda perché la loro funzione di freccia grassa ignora [, thisArg], ad esempio perché

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

è perché thisall'interno di quelle frecce le funzioni sono vincolate quando la funzione viene creata e sono impostate sul valore di thisnell'ambito più ampio, quindi l' thisArgargomento viene ignorato. Ho aggirato questo abbastanza facilmente dichiarando una nuova variabile in un ambito genitore:

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

Ecco un collegamento a ulteriori letture: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this


0

basato sulla risposta oddRaven e https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

l'ho fatto in 2 modi diversi. 1) utilizzando il modo funzione. 2) utilizzando il modo in linea.

//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

C'è un modo semplice per utilizzare la funzione di filtro, accedere a tutti i parametri e non complicarlo eccessivamente.

A meno che thisArg del callback non sia impostato su un altro ambito, il filtro non crea un proprio ambito e possiamo accedere ai parametri all'interno dell'ambito corrente. Possiamo impostare 'this' per definire un ambito diverso per accedere ad altri valori se necessario, ma per impostazione predefinita è impostato sull'ambito da cui viene chiamato. Si può vedere questo viene utilizzato per scopi angolari in questo stack .

L'uso di indexOf sta vanificando lo scopo del filtro e aggiungendo più overhead. Il filtro sta già attraversando l'array, quindi perché è necessario iterarlo di nuovo? Possiamo invece renderlo una semplice funzione pura .

Ecco uno scenario di caso d'uso all'interno di un metodo di classe React in cui lo stato ha un array chiamato elementi e utilizzando il filtro possiamo controllare lo stato esistente:

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
  });
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.