Использование карты массива для фильтрации результатов с помощью if

Я пытаюсь использовать карту массива для фильтрации объекта немного дальше, чтобы подготовить его к отправке на сервер для сохранения. Я могу отфильтровать до 1 ключевого значения, что отлично, но я хочу сделать это на 1 шаг дальше и проверить их на логическое внутри.

Итак, прямо сейчас это то, что у меня есть -

$scope.appIds = $scope.applicationsHere.map( function(obj){
        if(obj.selected == true){
            return obj.id;
        }
    });

Это отлично подходит для вытаскивания идентификатора, но я не хочу вставлять их в этот новый массив, если они выбрали value == false, поэтому я поставил условие для дальнейшего фильтрации. Это несколько работает, я получаю массив id, но идентификатор, который имеет .selected == false, все еще находится в массиве, просто со значением null. Итак, если у меня есть 4 объекта в объекте, а 2 из них ложны, это выглядит так:

 appIds = {id1, id2, null, null};

Мой вопрос - есть ли способ сделать это без нулевых значений. Спасибо за чтение!

Ответ 1

Вы ищете функцию .filter():

  $scope.appIds = $scope.applicationsHere.filter(function(obj) {
    return obj.selected;
  });

Это создаст массив, содержащий только те объекты, чье "выбранное" свойство true (или правдивое).

edit Извините, я получил кофе, и я пропустил комментарии - да, как отметил jAndy в комментарии, чтобы отфильтровать, а затем вырвать только значения "id", это будет:

  $scope.appIds = $scope.applicationsHere.filter(function(obj) {
    return obj.selected;
  }).map(function(obj) { return obj.id; });

Некоторые функциональные библиотеки (например Functional, которые, на мой взгляд, не получают достаточной любви) имеют функцию .pluck() для извлечения значений свойств из списка объектов, но родной JavaScript имеет довольно скудный набор таких инструментов.

Ответ 2

Вы должны использовать Array.prototype.reduce для этого. Я сделал небольшой тест JS для проверки производительности, чтобы убедиться, что он более производительный, чем .filter + .map.

$scope.appIds = $scope.applicationsHere.reduce(function(ids, obj){
    if(obj.selected === true){
        ids.push(obj.id);
    }
    return ids;
}, []);

Просто для ясности, вот пример .reduce я использовал в тесте JSPerf:

  var things = [
    {id: 1, selected: true},
    {id: 2, selected: true},
    {id: 3, selected: true},
    {id: 4, selected: true},
    {id: 5, selected: false},
    {id: 6, selected: true},
    {id: 7, selected: false},
    {id: 8, selected: true},
    {id: 9, selected: false},
    {id: 10, selected: true},
  ];
  
  	
var ids = things.reduce((ids, thing) => {
  if (thing.selected) {
    ids.push(thing.id);
  }
  return ids;
}, []);

console.log(ids)

Ответ 3

Вот некоторая информация, если кто-то столкнется с этим в 2019 году.

Я думаю, что уменьшение против карты + фильтр может быть в некоторой степени зависит от того, что вам нужно перебрать. Не уверен в этом, но уменьшить, кажется, медленнее.

Одно можно сказать наверняка - если вы ищете улучшения производительности, то способ написания кода чрезвычайно важен!

Здесь тест JS perf, который показывает огромные улучшения при полной типизации кода, а не проверяет значения "falsey" (например, if (string) {...}) или возвращает значения "falsey", где ожидается логическое значение.

Надеюсь, это поможет кому-то