Why does Array.filter(Number) filter zero out in JavaScript?

imckl picture imckl · Dec 25, 2018 · Viewed 6.9k times · Source

I'm trying to filter all non-numeric elements out from an array. We can see the desired output when using typeof. But with Number, it filters zero out.

Here's the example (tested in 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

If we use typeof, it doesn't filter zero, which was expected.

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

My question:

  1. What is the difference between the 'Number' and 'typeof' approaches?

  2. Number filters zero, but 'Number' itself literally contains zero, and this confuses me.

Answer

adiga picture adiga · Dec 25, 2018

Because 0 is one of the many falsy values in javascript

All these conditions will be sent to else blocks:

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

From the Array.prototype.filter() documentation:

filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a value that coerces to true

In your case the callback function is the Number. So your code is equivalent to:

[-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 (or values that coerces to true), the items which return 0 and NaN are ignored. So, it returns [-1, 1, 2, 3, 4]