web-dev-qa-db-fra.com

Comment passer un paramètre supplémentaire à la fonction de rappel dans la méthode Javascript .filter ()?

Je veux comparer chaque chaîne dans un tableau avec une chaîne donnée. Ma mise en œuvre actuelle est:

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

Cette fonction simple fonctionne, mais seulement parce que pour le moment wordToCompare est définie comme une variable globale, mais bien sûr, je veux éviter cela et le transmettre en tant que paramètre. Mon problème est que je ne sais pas comment définir startsWith () donc il accepte un paramètre supplémentaire, car je ne comprends pas vraiment comment les paramètres par défaut sont pris. J'ai essayé toutes les façons dont je peux penser et aucune d'entre elles ne fonctionne.

Si vous pouviez également expliquer comment les paramètres passés aux fonctions de rappel «intégrées» (désolé, je ne connais pas de meilleur terme pour ces fonctions) fonctionnent parfaitement.

90
agente_secreto

Assurez-vous que startsWith accepte le mot à comparer et renvoie une fonction qui sera ensuite utilisée comme fonction de filtrage/rappel:

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

addressBook.filter(startsWith(wordToCompare));

Une autre option serait d'utiliser Function.prototype.bind[MDN] (uniquement disponible dans les navigateurs prenant en charge ECMAScript 5, suivez un lien pour un shim pour les navigateurs plus anciens) et "corrigez" le premier argument:

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

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

Je ne comprends pas vraiment comment les paramètres par défaut sont nécessaires

Il n'y a rien de spécial à ce sujet. À un moment donné, filter appelle simplement le rappel et transmet l'élément actuel du tableau. Il s’agit donc d’une fonction appelant une autre fonction, dans ce cas le rappel que vous transmettez en tant qu’argument.

Voici un exemple de fonction similaire:

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;
}
140
Felix Kling

Le second paramètre de filtre définira this à l'intérieur du rappel.

arr.filter(callback[, thisArg])

Pour que vous puissiez faire quelque chose comme:

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

// ...
var Word = "SOMETHING";

addressBook.filter(function(element){
    return startsWith(element, Word);
});
11
James Montagne

Pour ceux qui recherchent une alternative à l'ES6 à l'aide des fonctions de flèche, vous pouvez procéder comme suit.

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

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

Version mise à jour avec includes :

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

Vous pouvez utiliser la fonction de flèche dans un filtre, comme ceci:

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

Les fonctions fléchées sur MDN

Une expression de fonction flèche a une syntaxe plus courte que celle des expressions de fonction et lie lexicalement la valeur this (ne lie pas ses propres arguments this, arguments, super ou new.target). Les fonctions de flèche sont toujours anonymes. Ces expressions de fonction conviennent mieux aux fonctions non-méthodes et ne peuvent pas être utilisées en tant que constructeurs.

2
oddRaven

Pour ceux qui se demandent pourquoi leur fonction de flèche grasse ignore [, thisArg], par exemple. Pourquoi

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

c'est parce que this à l'intérieur de ces flèches est lié lorsque la fonction est créée et que sa valeur est définie sur this dans la portée englobante plus large, l'argument thisArg est donc ignoré. J'ai facilement contourné cela en déclarant une nouvelle variable dans une portée parente:

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

Voici un lien vers d'autres lectures: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this

1
Jimmy Kettler

Il existe un moyen simple d’utiliser la fonction de filtrage, d’accéder à tous les paramètres et de ne pas trop le compliquer. 

Si le callback thisArg n'est pas défini sur un autre filtre de portée, il ne crée pas sa propre portée et nous pouvons accéder aux paramètres de la portée actuelle. Nous pouvons définir "this" pour définir une autre portée afin d'accéder à d'autres valeurs si nécessaire, mais par défaut, elle est définie sur la portée depuis laquelle elle est appelée. Vous pouvez voir que this est utilisé pour les champs angulaires dans cette pile .

Utiliser indexOf annule la fonction de filtre et ajoute davantage de temps système. Le filtre traverse déjà le tableau, alors pourquoi devons-nous le parcourir à nouveau? Nous pouvons plutôt en faire une simple fonction pure .

Voici un scénario de cas d'utilisation dans une méthode de classe React où l'état a un tableau appelé items, et en utilisant un filtre, nous pouvons vérifier l'état existant:

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

basé sur oddRaven answer .__ et https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

je l'ai fait 2 manière différente. 1) en utilisant la fonction. 2) en utilisant le chemin en ligne. 

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