Як передати додатковий параметр функції зворотного виклику методом Javascript .filter ()?


104

Я хочу порівняти кожну рядок у масиві із заданою строкою. Моя поточна реалізація:

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

Ця проста функція працює, але лише тому, що зараз wordToCompare встановлюється як глобальна змінна, але, звичайно, я хочу цього уникати і передавати його як параметр. Моя проблема полягає в тому, що я не знаю, як визначити startWith (), тому він приймає один додатковий параметр, тому що я не розумію, як передаються параметри за замовчуванням, які він приймає. Я спробував всі різні способи, які я можу придумати, і жоден з них не працює.

Якщо ви також можете пояснити, як передані параметри функціям "вбудованого" зворотного виклику (вибачте, я не знаю кращого терміна для них), що було б чудово

Відповіді:


152

Зробіть 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;
}

1
Добре зараз я розумію. Я намагався передати параметри безпосередньо функції зворотного виклику ... Мені справді потрібно працювати над своїм JavaScript. Дякую Фелікс, ваша відповідь дуже корисна
— agente_secreto

Що щодо передачі додаткових аргументів? Я спробував передати масив аргументів, але це, здається, не вдалося
— геотеорія

@geotheory: що з ними? ви передаєте кілька аргументів, як і будь-якій іншій функції.
— Фелікс Клінг

прив'язувати (це) після назви функції разом із ланцюгом filter () допомогло мені використовувати .цю функцію всередині. Дякую.
— Сагар Хатрі

108

Другий параметр фільтра встановить це всередині зворотного дзвінка.

arr.filter(callback[, thisArg])

Таким чином, ви можете зробити щось на кшталт:

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

7
Я знайшов, що це найкраща відповідь.
— Джиаф Гілберт

тому тепер новий масив буде призначений об’єкту wordToCompare, правда? Як пізніше можна отримати доступ до нового масиву за допомогою об’єкта wordToCompare?
— Badhon Jain

найкраща відповідь. працює ідеально як для фільтра, і для пошуку. І є документацією на WC3 для обох: thisValue - Необов’язково. Значення, яке передається функції, яка використовується як її "це" значення. Якщо цей параметр порожній, значення "undefined" буде передано як його "this" значення
— richaa

1
@TarekEldeeb просто передай створений вами об’єкт{one: 'haha', two:'hoho'}
— toddmo

2
Це чудовий приклад того, як можуть бути величезні розбіжності між відповідями щодо складності та наскільки вони можуть бути спроможними проти того, наскільки вони можуть бути
— простими

13

Для тих, хто шукає альтернативу 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);
}

Чи є спосіб передавати інший параметр від елемента, індексу та масиву? Наприклад, я хочу передати змінну X.
— leandrotk

@leandrotk у цьому випадку "wordToCompare" - це змінна "X", яку слід передавати.
— GetBackerZ

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

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

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

4

Ви можете використовувати функцію стрілки всередині фільтра, наприклад:

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

Функції стрілки на MDN

Вираз функції стрілки має коротший синтаксис порівняно з функційними виразами і лексично пов'язує це значення (не пов'язує його власне це, аргументи, супер або new.target). Функції стрілок завжди анонімні. Ці вирази функцій найкраще підходять для неметодних функцій, і їх не можна використовувати як конструктори.


Примітка: Не підтримується в IE
— Луїс Лав'єрі

1

Для всіх, хто цікавиться, чому їх жирова стрілка ігнорується [, 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


0

на основі відповіді oddRaven та https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

я зробив це 2 по-різному. 1) використовуючи функціональний спосіб. 2) використовуючи inline спосіб.

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

Існує простий спосіб використовувати функцію фільтра, отримати доступ до всіх параметрів і не надто ускладнювати її.

Якщо цей аргумент для зворотного дзвінка встановлений для іншого фільтра діапазону, він не створює власну область, і ми можемо отримати доступ до парам в поточній області. Ми можемо встановити "це", щоб визначити іншу область, щоб отримати доступ до інших значень, якщо це потрібно, але за замовчуванням вона встановлена ​​в області, з якої вона викликана. Ви можете бачити, як це використовується для кутових областей у цій стеці .

Використання 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
  });
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.