In this case, you're better off with forEach , but I am addressing your question about why !predicate didn't work (and how you can do something like that) below.
First, a simple forEach solution:
Prosiac:
function test(array, predicate){ var filterTrue = []; var filterFalse = []; array.forEach(function(value) { if (predicate(value)) { filterTrue.push(value); } else { filterFalse.push(value); } });
A bit more concise:
function test(array, predicate){ var filterTrue = []; var filterFalse = []; array.forEach(function(value) { (predicate(value) ? filterTrue : filterFalse).push(value); });
Aside, I tried:
var filterFalse = array.filter(!predicate);
But this does not seem to work for reasons that I am still trying to understand.
It should be:
var filterFalse = array.filter(function(entry) { return !predicate(entry); });
... and it really will work, but that means you make two passes through the array and call the predicate twice for each element. Therefore, I recommended forEach : only one pass through the array is required and only one predicate call for each record.
The reason your var filterFalse = array.filter(!predicate); didn't work, is that it takes a predicate variable that contains a reference to the function and logically inverts it with ! . The logically inverted version of the reference to a nonzero object (functions are objects) is false , so you actually passed false to filter .
More fully: unary ! forces its operand to have a boolean value and then returns the opposite ( false for true and true for false ). Thus !predicate will result in false for any predicate value that will depend on true (in other words, "true" values) and will lead to true for any predicate value that will depend on false (otherwise called "false" values). So what are the “true” and “false” values? False, 0 , null , undefined , NaN and, of course, false ; The "right" values are all others, including all references to null objects.
If you program a lot with predicates and want to say “not a predicate” and get a function that gives you an inverted result, you can do it like this:
function not(predicate) { return function() { return !predicate.apply(this, arguments); }; }
and then:
var filterFalse = array.filter(not(predicate));
This function not works as follows: it returns a new function that, when called, will call the predicate function that you gave it, passing by the value this with which it was called, and all the arguments that it called with (via Function#apply - spec | MDN ), logically inverting the return value obtained from the predicate, and then returning this inverted value.
But again, using this, it takes two passes through the array. Sometimes with high-level abstractions, however, this may be preferable to the forEach solution.
Finally, if you do a lot of this “or /” a lot, you can, of course, make a function for this:
function divvyUp(array, predicate) { var filterTrue = [], filterFalse = []; array.forEach(function(value) { (predicate(value) ? filterTrue : filterFalse).push(value); }); return { filterTrue: filterTrue, filterFalse: filterFalse }; }