为何filter方法使用三元运算符时效果与if条件语句不一致?
Array.filter() behave differently with ternary operator vs if/else? Great question! Let's break down exactly what's happening here—it all boils down to how filter() evaluates the return value of its callback, and what each of your code snippets is actually sending back.
First, a quick reminder of how filter() works
filter() keeps an element in the resulting array only if the callback returns a "truthy" value (any value that evaluates to true in a boolean context). If the callback returns a "falsy" value (undefined, null, 0, false, '', NaN), the element gets excluded.
Let's start with your working if/else version
let numbers = [-1, -2, -3, 1, 2, 3]; let negatives = []; let positives = numbers.filter(num => { if(num > 0) { return num; // positives array => [1, 2, 3] } else { negatives.push(num); // negatives array => [-1, -2, -3] } })
What's the callback really returning here?
- For positive numbers (
num > 0): You returnnum(1, 2, 3). All of these are truthy, sofilter()keeps them. - For negative numbers: There's no explicit
returnstatement. In JavaScript, functions automatically returnundefinedif no return value is specified.undefinedis falsy, sofilter()excludes these elements.
That's why this version behaves exactly as you expect.
Now let's unpack the ternary operator issue
let positives = numbers.filter(num => num > 0 ? num : negatives.push(num)); // positives array => [-1, -2, -3, 1, 2, 3] // negatives array => [-1, -2, -3]
The problem lies in what the else branch of the ternary returns. Here's a key detail you might have missed: Array.push() returns the new length of the array after adding the element.
So when you run negatives.push(num) for each negative:
- First push of
-1returns1(truthy) - Second push of
-2returns2(truthy) - Third push of
-3returns3(truthy)
This means your ternary is effectively doing:
- For positives: Return
num(truthy → keep the element) - For negatives: Return
1,2,3(all truthy → keep the element)
Since every iteration returns a truthy value, filter() keeps all elements from the original array—hence your unexpected full array result.
How to fix the ternary version
If you want to stick with a ternary, you need to make sure the else branch returns a falsy value after pushing the negative number. You can use the comma operator to run the push first, then return false:
let positives = numbers.filter(num => num > 0 ? true : (negatives.push(num), false));
Or, for better readability, stick with the explicit if/else (and even better, explicitly return true/false instead of relying on the number's truthiness):
let positives = numbers.filter(num => { if (num > 0) { return true; } else { negatives.push(num); return false; } });
内容的提问来源于stack exchange,提问作者Khaled-Ahmed

