Странные результаты метода .filter в javascript

274
19 августа 2017, 04:00

Добрый вечер. Это снова я и мой цирк вопросов )) Есть два массива - массив объектов и просто массив чисел:

var numbers1 = [{prop: 1},{prop: 2},{prop: 3},{prop: 4},{prop: 5},{prop: 6}];
var numbers2 = [2,3,4,6];

Почему .filter над numbers1 в такой редакции:

var mynumbers = numbers1.filter(function(number1) {
    var bufferNumber;
    numbers2.forEach(function(number2) {
        if (number1.prop == number2)
        {
            bufferNumber = number1;
            return bufferNumber;
        }
    });
    return bufferNumber;
});

выдает в консоль ожидаемое [ { prop: 2 }, { prop: 3 }, { prop: 4 }, { prop: 6 } ], а вариант без объявления буфферной переменной:

var mynumbers = numbers1.filter(function(number1) {
    numbers2.forEach(function(number2) {
        if (number1.prop == number2)
            return number1;
    });
    return number1;
});

не фильтрует массив numbers1, а возвращает его неотфильтрованный вариант

[ { prop: 1 },
  { prop: 2 },
  { prop: 3 },
  { prop: 4 },
  { prop: 5 },
  { prop: 6 } ]

?

Answer 1

Все очень просто: если коллбэк, переданный в функцию filter, возвращает результат соответствующий true - элемент помещается в результат, если false - не помещается.

В примере, в массиве numbers содержаться объекты, которые всегда соответствуют true, поэтому во втором примере, если выкинуть из него внутренний цикл, который ни на что не влияет получим

var mynumbers = numbers1.filter(function(number1) {
    return number1;
});

откуда видно, что возвращая элемент этого массива, все элементы удовлетворяют условию и помещаются в результат.

С первым случаем ситуация интереснее.

Во-первых, возвращается временная переменная, она объявлена внутри функции коллбэка, и на каждой итерации своя.

Во-вторых, значение ей присваивается в зависимости от условия, и в противном случае является undefined, который соответствует false, поэтому в случае если значение свойства не было найдено значение переменной осталось undefiend и проверяемый элемент массива не заносился в результат.

небольшое отступление: return внутри коллбэка переданного функции forEach не прерывает обход коллекции. В данном случае проще проверять вхождение с помощью функции indexOf или some

var numbers1 = [{ 
  prop: 1 
}, { 
  prop: 2 
}, { 
  prop: 3 
}, { 
  prop: 4 
}, { 
  prop: 5 
}, { 
  prop: 6 
}]; 
var numbers2 = [2, 3, 4, 6]; 
document.write('temp variable:', '<br>') 
var mynumbers = numbers1.filter(function(number1) { 
  var bufferNumber; 
  numbers2.forEach(function(number2) { 
    if (number1.prop == number2) { 
      bufferNumber = number1; 
      return bufferNumber; 
    } 
  }); 
  document.write('el:', JSON.stringify(number1), '->', !!bufferNumber, '<br>'); 
  return bufferNumber; 
}); 
document.write('result: ', JSON.stringify(mynumbers), '<br>'); 
 
document.write('<br>', 'without temp variable:', '<br>') 
var mynumbers = numbers1.filter(function(number1) { 
  numbers2.forEach(function(number2) { 
    if (number1.prop == number2) 
      return number1; 
  }); 
  document.write('el:', JSON.stringify(number1), '->', !!number1, '<br>'); 
  return number1; 
}); 
document.write('result: ', JSON.stringify(mynumbers), '<br>'); 
document.write('<br>', 'with indexOf:', '<br>') 
var mynumbers = numbers1.filter(function(number1) { 
 
  document.write('el:', JSON.stringify(number1), '->', numbers2.indexOf(number1.prop) > -1, '<br>'); 
  return numbers2.indexOf(number1.prop) > -1; 
}); 
document.write('result: ', JSON.stringify(mynumbers), '<br>'); 
 
document.write('<br>', 'with some function:', '<br>') 
var mynumbers = numbers1.filter(function(number1) { 
 
  document.write('el:', JSON.stringify(number1), '->', numbers2.some(function(num) { 
    return num == number1.prop 
  }), '<br>'); 
  return numbers2.some(function(num) { 
    return num == number1.prop 
  }); 
}); 
document.write('result: ', JSON.stringify(mynumbers), '<br>');

READ ALSO
Код выше срабатывает после кода ниже

Код выше срабатывает после кода ниже

Проблема заключается в том что сначала выводятся 2 нижних алерта а потом верхний и я не могу понять как это вообще возможно

235
JS. Как удалить &lt;aside data-sidebar&gt;&lt;/aside&gt; оставив все что внутри?

JS. Как удалить <aside data-sidebar></aside> оставив все что внутри?

Есть часть кода html (фильтр товара), он размещен внутри

184
Отобразить только первые 5 блоков [дубликат]

Отобразить только первые 5 блоков [дубликат]

На данный вопрос уже ответили:

311
Почему не видит контроллер в Angular?

Почему не видит контроллер в Angular?

Html: Сам контроллер: Вот что выскакивает в браузере:

239