Як передати додатковий параметр функції зворотного виклику методом 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.