Почему Array.filter(Number) фильтрует обнуление в JavaScript?

Я пытаюсь отфильтровать все нечисловые элементы из массива. Мы можем видеть желаемый результат при использовании typeof. Но с Number он фильтрует ноль.

Вот пример (проверено в Chrome Console):

[-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(Number)
// Which output with zero filtered out:
[-1, 1, 2, 3, 4]  // 0 is filtered

Если мы используем typeof, он не фильтрует ноль, что и ожидалось.

// code
[-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(n => typeof n === 'number')
// output
[-1, 0, 1, 2, 3, 4, 0]

Мой вопрос:

  1. В чем разница между подходами "число" и "типоф"?

  2. Число фильтрует ноль, но само "Число" буквально содержит ноль, и это меня смущает.

Ответ 1

Потому что 0 является одним из многих falsy значений в JavaScript

Все эти условия будут отправлены в else блоки:

if (false)
if (null)
if (undefined)
if (0)
if (NaN)
if ('')
if ("")
if ('')

Из документации Array.prototype.filter():

filter() вызывает предоставленную callback один раз для каждого элемента в массиве и создает новый массив всех значений, для которых обратный вызов возвращает значение, которое приводит к истине

В вашем случае функцией обратного вызова является Number. Итак, ваш код эквивалентен:

[-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(a => Number(a)) 

// Number(0) -> 0
// Number(Number(0)) -> 0
// Number('') -> 0
// Number('test') -> NaN
// When filter function picks *truthy* values, all the above are ignored
// So, it returns [-1, 1, 2, 3, 4]

Ответ 2

Чтобы не допустить фильтрации ложного нуля, вы можете использовать другой обратный вызов для получения только числовых значений: Number.isFinite

console.log([-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(Number.isFinite))

Ответ 3

Ожидаемое поведение

Это поведение не уникально для использования Number в качестве функции фильтра. Функция фильтра, которая просто возвращает значение 0, также удалит его из списка.

var a = [-1, 0, 1, 2, 3, 4, Number(0), '', 'test'].filter(v => v)
console.log(a); // [-1, 1, 2, 3, 4, "test"]

Ответ 4

Ноль - это фальшивое значение. Typeof всегда возвращает логическое значение. Когда возвращается число 0, оно возвращается к тесту и, следовательно, возвращается как ложное, поэтому нулевое число отфильтровывается.

Ответ 5

Это потому, что 0 - ложное значение, которое возвращает false, а все, что возвращает false для функции фильтра, отфильтровывается из нового массива.

Документация

https://developer.mozilla.org/en-US/docs/Glossary/Falsy

Ответ 6

Когда вы используете Number в фильтре, фактически он передает каждый элемент массива конструктору Number, а в случае строки или 0 Number возвращает NaN или 0, и оба они имеют значение false, поэтому фильтр отфильтровывает оба из них.

тогда как когда вы используете typeof, тогда 0 имеет тип "число", поэтому он возвращает true, а метод filter не фильтрует его