Как передать дополнительный параметр функции обратного вызова в метод Javascript.filter()?
Я хочу сравнить каждую строку в массиве с заданной строкой. Моя текущая реализация:
function startsWith(element) {
return element.indexOf(wordToCompare) === 0;
}
addressBook.filter(startsWith);
Эта простая функция работает, но только потому, что сейчас wordToCompare устанавливается как глобальная переменная, но, конечно, я хочу избежать этого и передать его как параметр. Моя проблема в том, что я не уверен, как определить startWith(), поэтому он принимает один дополнительный параметр, потому что я действительно не понимаю, как передаются параметры по умолчанию. Я пробовал все разные способы, о которых я могу думать, и никто из них не работает.
Если бы вы могли также объяснить, как переданные параметры "встроены" в функции обратного вызова (извините, я не знаю лучшего термина для них), это было бы замечательно
Ответы
Ответ 1
Сделать startsWith
принять слово для сравнения и вернуть функцию, которая затем будет использоваться в качестве функции фильтра/обратного вызова:
function startsWith(wordToCompare) {
return function(element) {
return element.indexOf(wordToCompare) === 0;
}
}
addressBook.filter(startsWith(wordToCompare));
Другим вариантом будет использование Function.prototype.bind
[MDN] (доступно только в браузере, поддерживающем ECMAScript 5, следуйте ссылке для прокладки для старых браузеров) и "исправить" первый аргумент:
function startsWith(wordToCompare, element) {
return element.indexOf(wordToCompare) === 0;
}
addressBook.filter(startsWith.bind(this, wordToCompare));
Я действительно не понимаю, как передаются параметры по умолчанию
В этом нет ничего особенного. В какой-то момент filter
просто вызывает обратный вызов и передает текущий элемент массива. Таким образом, это функция, вызывающая другую функцию, в этом случае обратный вызов вы передаете как аргумент.
Вот пример аналогичной функции:
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;
}
Ответ 2
Второй параметр фильтра установит этот внутри обратного вызова.
arr.filter(callback[, thisArg])
Итак, вы можете сделать что-то вроде:
function startsWith(element) {
return element.indexOf(this) === 0;
}
addressBook.filter(startsWith, wordToCompare);
Ответ 3
function startsWith(element, wordToCompare) {
return element.indexOf(wordToCompare) === 0;
}
// ...
var word = "SOMETHING";
addressBook.filter(function(element){
return startsWith(element, word);
});
Ответ 4
Для тех, кто ищет альтернативу ES6, используя функции стрелок, вы можете сделать следующее.
let startsWith = wordToCompare => (element, index, array) => {
return element.indexOf(wordToCompare) === 0;
}
// where word would be your argument
let result = addressBook.filter(startsWith("word"));
Обновленная версия включает:
const startsWith = wordToCompare => (element, index, array) => {
return element.includes(wordToCompare);
}
Ответ 5
Вы можете использовать функцию стрелки внутри фильтра, например:
result = addressBook.filter(element => element.indexOf(wordToCompare) === 0);
Функции стрелок в MDN
Выражение функции стрелки имеет более короткий синтаксис по сравнению с выражением функции и лексически связывает это значение (не связывает его собственные, аргументы, супер или new.target). Функции стрелок всегда анонимны. Эти функциональные выражения лучше всего подходят для функций не-метода, и они не могут использоваться как конструкторы.
Ответ 6
Для тех, кто задается вопросом, почему их функция толстой стрелки игнорирует [, thisArg]
, например. почему
["DOG", "CAT", "DOG"].filter(animal => animal === this, "DOG")
возвращает []
потому что this
внутри этих функций стрелки привязывается при создании функции и устанавливается в значение this
в более широкой области охвата, поэтому аргумент thisArg
игнорируется. Я обошел это довольно легко, объявив новую переменную в родительской области:
let bestPet = "DOG";
["DOG", "CAT", "DOG"].filter(animal => animal === bestPet);
=> ["DOG", "DOG"]
Вот ссылка на некоторое чтение:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this
Ответ 7
на основе ответа oddRaven
а также
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
Я сделал это по-другому.
1) используя функциональный путь.
2) с использованием встроенного способа.
//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) ;
Ответ 8
Существует простой способ использовать функцию фильтра, получить доступ ко всем параметрам, а не усложнять его.
Если обратный вызов thisArg не установлен на другой фильтр области, он не создает свою собственную область, и мы можем получить доступ к параметрам в текущей области. Мы можем установить 'this' для определения другой области действия, чтобы получить доступ к другим значениям, если это необходимо, но по умолчанию он установлен в область, из которой он вызвал. Вы можете видеть, что это используется для Angular областей в этом стеке.
Использование indexOf приводит к поражению цели фильтра и добавлению дополнительных накладных расходов. Фильтр уже проходит через массив, так зачем нам повторять его снова? Мы можем вместо этого сделать его простой чистую функцию.
Здесь сценарий использования в методе класса React, в котором состояние имеет массив, называемый элементами, и с помощью фильтра мы можем проверить существующее состояние:
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
});
}