Imagine you have an array and you would like to select positive odd numbers. Using EcmaScript5 array iterator you write:
1 | var numbers = [1, 5, -3, 2, 0, null, 0, 7]; |
Works correctly, but looks ugly and requires a comment line. Let's simplify this.
step 1: underscore-contrib
Let's bring underscore-contrib library with lots of predicates:
npm install --save underscore-contrib
The filtering function now does not need an explanation line
1 | var _ = require('underscore-contrib'); |
I still do not like the boiler plate function filterNumbers
step 2: create AND predicate
It is easy to write a small utility function and to connect multiple conditions into single one
1 | function and() { |
and creates a new function out of arguments, the returned function evaluateAnd calls every argument function and returns true only if all predicates return truthy value.
1 | selected = numbers.filter(and(_.isPositive, _.isOdd)); |
This is much cleaner filtering code.
step 3: clean up AND and create OR
Lets make sure that and function is robust by checking all arguments to be functions
1 | function and() { |
For completeness sake, lets also create OR function that returns true if some predicate is truthy:
1 | function or() { |
Update 1 - short AND conditions using Ramda library
One can run multiple predicates using the Ramda library. It has a convenient R.allPass method. For example, to execute a function if the argument is even and the user is authorized
1 | function isEven(x) { |
We can refactor the above R.allPass
call for clarity. First, let us move list of conditions outside.
1 | function foo(x) { |
Notice that the argument x
is passed to each individual condition function. What if
the different conditions expect different arguments? We can partially apply each function first.
1 | function foo(x) { |
Imagine we need to simply check if the passed value x
is truthy. Unfortunately, R.allPass
requires each condition to be a function and not a primitive value. Thus we cannot write
1 | var conditions = [ |
We can use a helper function in this case that would return x
1 | var conditions = [ |
One last trick: if you do not want to create an array of conditions when calling R.allPass
, you
can unroll it to accept a separate list of arguments using R.unapply.
1 | var arePassing = R.unapply(R.allPass); |
related: refactor OR