¿Cómo paso un parámetro adicional a la función de devolución de llamada en el método Javascript .filter ()?

104

Quiero comparar cada cadena en una matriz con una cadena determinada. Mi implementación actual es:

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

Esta función simple funciona, pero solo porque en este momento wordToCompare se está configurando como una variable global, pero, por supuesto, quiero evitar esto y pasarlo como un parámetro. Mi problema es que no estoy seguro de cómo definir startsWith (), por lo que acepta un parámetro adicional, porque realmente no entiendo cómo se pasan los parámetros predeterminados que toma. He intentado todas las formas diferentes en las que puedo pensar y ninguna de ellas funciona.

Si también pudiera explicar cómo funcionan los parámetros pasados ​​a las funciones de devolución de llamada 'integradas' (lo siento, no conozco un término mejor para estas), sería genial

agente_secreto
fuente

Respuestas:

152

Haga que startsWithacepte la palabra con la que comparar y devuelva una función que luego se usará como función de filtro / devolución de llamada:

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

addressBook.filter(startsWith(wordToCompare));

Otra opción sería usar Function.prototype.bind [MDN] (solo disponible en el navegador compatible con ECMAScript 5, siga un enlace para una corrección para navegadores más antiguos) y "corregir" el primer argumento:

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

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

Realmente no entiendo cómo se pasan los parámetros predeterminados que toma

No tiene nada de especial. En algún momento, filtersimplemente llama a la devolución de llamada y pasa el elemento actual de la matriz. Entonces es una función que llama a otra función, en este caso la devolución de llamada que pasa como argumento.

A continuación, se muestra un ejemplo de una función similar:

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
fuente
1
Bueno, ahora lo entiendo. Estaba tratando de pasar los parámetros directamente a la función de devolución de llamada ... Realmente necesito trabajar en mi JavaScript. Gracias Felix, tu respuesta es muy útil
agente_secreto
¿Qué hay de pasar argumentos adicionales? He intentado pasar una serie de argumentos, pero que parece fallar
geotheory
@geotheory: ¿qué pasa con ellos? pasa múltiples argumentos como a cualquier otra función.
Felix Kling
enlazar (esto) después del nombre de la función junto con el encadenamiento de filter () me ayudó a usar esta función interna. Gracias.
Sagar Khatri
108

El segundo parámetro de filtro establecerá esto dentro de la devolución de llamada.

arr.filter(callback[, thisArg])

Entonces podrías hacer algo como:

function startsWith(element) {
    return element.indexOf(this) === 0;
}
addressBook.filter(startsWith, wordToCompare);
Jeff
fuente
7
Encontré que esta es la mejor respuesta.
Jeaf Gilbert
así que ahora la nueva matriz se asignará al objeto wordToCompare, ¿verdad? ¿Cómo se puede acceder a la nueva matriz más tarde usando el objeto wordToCompare?
Badhon Jain
la mejor respuesta. funciona perfecto tanto para filtrar como para buscar. Y es según la documentación WC3 para ambos: thisValue - Opcional. Un valor que se pasará a la función que se utilizará como su valor "este". Si este parámetro está vacío, el valor "indefinido" se pasará como su valor "este"
richaa
1
@TarekEldeeb acaba de pasar un objeto que hagas{one: 'haha', two:'hoho'}
toddmo
2
Este es un gran ejemplo de cómo puede haber grandes diferencias entre respuestas en cuanto a complejidad y cómo contorneado que pueden ser frente a lo simple que puede ser
toddmo
13

Para aquellos que buscan una alternativa a ES6 usando las funciones de flecha, pueden hacer lo siguiente.

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

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

La versión actualizada que usa incluye :

const startsWith = wordToCompare => (element, index, array) => {
  return element.includes(wordToCompare);
}
jhamPac
fuente
¿Hay alguna forma de pasar un parámetro diferente de elemento, índice y matriz? Por ejemplo, quiero pasar una variable X.
leandrotk
@leandrotk en este caso, "wordToCompare" es la variable "X" que se debe pasar.
GetBackerZ
11
function startsWith(element, wordToCompare) {
    return element.indexOf(wordToCompare) === 0;
}

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

addressBook.filter(function(element){
    return startsWith(element, word);
});
James Montagne
fuente
4

Puede usar la función de flecha dentro de un filtro, como este:

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

Funciones de flecha en MDN

Una expresión de función de flecha tiene una sintaxis más corta en comparación con las expresiones de función y enlaza léxicamente el valor this (no enlaza su propio this, argumentos, super o new.target). Las funciones de flecha son siempre anónimas. Estas expresiones de función son las más adecuadas para funciones que no son de método y no se pueden usar como constructores.

OddRaven
fuente
Nota: No compatible con IE
Luis Lavieri
1

Para cualquiera que se pregunte por qué se ignora su función de flecha gruesa [, thisArg], por ejemplo, por qué

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

es porque thisdentro de esas funciones de flecha están vinculadas cuando se crea la función y se establecen en el valor de thisen el ámbito abarcador más amplio, por lo que el thisArgargumento se ignora. Lo solucioné con bastante facilidad al declarar una nueva variable en un ámbito principal:

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

Aquí hay un enlace para leer más: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this

JKettler
fuente
0

basado en la respuesta de oddRaven y https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

Lo hice de 2 formas diferentes. 1) usando la forma de función. 2) usando forma en línea.

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

Hay una manera fácil de usar la función de filtro, acceder a todos los parámetros y no complicarlo demasiado.

A menos que el thisArg de la devolución de llamada se establezca en otro ámbito, el filtro no crea su propio ámbito y podemos acceder a los parámetros dentro del ámbito actual. Podemos configurar 'esto' para definir un alcance diferente para acceder a otros valores si es necesario, pero de forma predeterminada se establece en el alcance desde el que se llama. Puede ver que esto se usa para ámbitos angulares en esta pila .

El uso de indexOf está anulando el propósito del filtro y agrega más gastos generales. El filtro ya está pasando por la matriz, entonces, ¿por qué tenemos que repetirlo de nuevo? En su lugar, podemos convertirlo en una función pura simple .

Aquí hay un escenario de caso de uso dentro de un método de clase React donde el estado tiene una matriz llamada elementos , y al usar el filtro podemos verificar el estado existente:

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
  });
}
Marrón
fuente