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.