0

I just found this problem when use Array​.prototype​.filter(), someone can explain to me why?

I have these two arrays

[0, NaN, NaN, NaN]

[1, NaN, NaN, NaN]

When I call filter() using Number type filter the return of first is an empty array with instead the second return is an array.

I think the check on 0 as a Number fail but why? I tried to construct a Number with 0 and it work obviously.

console.log([0, NaN, NaN, NaN].filter(Number)); // []

console.log([1, NaN, NaN, NaN].filter(Number)); // [1]

// other examples
console.log([0, 1, 2, 3].filter(Number)); // [1, 2, 3]

console.log([1, 2, 3, 4].filter(Number)); // [1, 2, 3, 4]

console.log([0.1, 0.2, 0.3, 0.4].filter(Number)); // [0.1, 0.2, 0.3, 0.4]

console.log([1.1, 2.2, 3.3, 4.4].filter(Number)); // [1.1, 2.2, 3.3, 4.4]

console.log([-1, -2, -3, -4].filter(Number)); // [-1, -2, -3, -4]

Thank you in advance guys and girls.

3
  • 1
    Number(0) returns 0 which is falsey. Why would you expect that to just pass? Number doesn't return boolean values, after all. Commented Apr 24, 2019 at 10:35
  • "When I call filter() using Number type filter" wait, that's not a type filter at all. You should probably re-check the documentation on what filter does - it expects a predicate, and Number is not one. Commented Apr 24, 2019 at 10:37
  • The Number() function doesn't tell you whether something is a number, it converts it to a number. Commented Apr 24, 2019 at 10:37

7 Answers 7

2

Array.filter

The filter() method creates a new array with all elements that pass the test implemented by the provided function.

0 & NaN are both falsey values, hence, they are removed by the filter function.

To filter in 0, you can use isNaN like following

console.log([0, NaN, NaN, NaN].filter(v => !isNaN(v))); // [0]

Sign up to request clarification or add additional context in comments.

3 Comments

Also as side note it's better to use Number.isNaN() - isNaN('x') is true, because it first convert it string to number.
If this is duplicate why it has 7 answers ;(
@jcubic - Thank you for your input and I totally agree with you. However, as the scope of question was lying around numeric values and NaN, i opted in for isNaN.
2

If the return value from the filter callback is falsey, the resulting item will not be included in the resulting array. Because 0 is falsey, just like NaN is falsey, it does not get included.

Non-zero, non-NaN numbers like 1, 2, 3, -1, -2, -3 are not falsey, so they do get included.

To filter out NaN values, consider using Number.isNaN instead:

console.log([0, NaN, NaN, NaN].filter(item => !Number.isNaN(item)));
console.log([1, NaN, NaN, NaN].filter(item => !Number.isNaN(item)));
console.log([0, 1, 2, 3].filter(item => !Number.isNaN(item)));
console.log([1, 2, 3, 4].filter(item => !Number.isNaN(item)));
console.log([0.1, 0.2, 0.3, 0.4].filter(item => !Number.isNaN(item)));
console.log([1.1, 2.2, 3.3, 4.4].filter(item => !Number.isNaN(item)));
console.log([-1, -2, -3, -4].filter(item => !Number.isNaN(item)));

If you want to make sure that the item is a number too, then check typeof as well:

const callback = item => typeof item === 'number' && !Number.isNaN(item);

console.log([0, NaN, NaN, NaN].filter(callback));
console.log([1, NaN, NaN, NaN].filter(callback));
console.log([0, 1, 2, 3].filter(callback));
console.log([1, 2, 3, 4].filter(callback));
console.log([0.1, 0.2, 0.3, 0.4].filter(callback));
console.log([1.1, 2.2, 3.3, 4.4].filter(callback));
console.log([-1, -2, -3, -4].filter(callback));

1 Comment

If OP expects a filter for numbers, then I guess you also need to check typeof item === "number", otherwise stuff like "1" would not be filtered out.
1

Because 0 is falsy

It will only work on Truthy values.

you can about truthy values here https://developer.mozilla.org/en-US/docs/Glossary/Truthy

Comments

1

It's because of something called 'falsey'. you pass Filter a function, and if that function returns false, or a falsey value, for a particular item in the array, that doesn't get returned in the final array.

Comments

1

The callback passed to Array.filter is supposed to return true or false. Number(0) produces the number 0 which is coerced to false, which explains why you get [] as the result.

Comments

1

In the filter function you enter a condition, the result of number(0) is 0 and 0 is a negative condition (like NaN), on the other hand Number(1) is 1 or Number(0.1) is 0.1 which give rise to a positive condition.

Examples:

[-1, -2, -3, -4].filter(()=>0.1);  // [ -1, -2, -3, -4 ]
[-1, -2, -3, -4].filter(()=>0));   // []
[-1, -2, -3, -4].filter(()=>NaN);  // []

Comments

1

Number coverts the argument to the number data type, so it is like a null-operation on your actual sample data: they already are of type number. Filter will only retain truthy values, and both 0 and NaN are not truthy.

What you could use instead is:

.filter(Number.isFinite)

This will exclude NaN, Infinity, -Infinity, and data that is not of numeric data type, but will keep all finite numbers.

If you need other data types (e.g. a string like "23") to be converted to number and retained after the filter, then chain:

.map(Number).filter(Number.isFinite)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.