I try to use in my app, simple comparator to filter some data with passing string filter instead function as eg. passed to [].filter
Comparator should return function which will be a filter.
var comparator = function( a, b, c ) {
switch( b ){
case '>=': return function() { return this[a] >= c;}; break;
case '<=': return function() { return this[a] <= c;}; break;
case '<': return function() { return this[a] < c;}; break;
case '>': return function() { return this[a] > c;}; break;
case '=': return function() { return this[a] == c;}; break;
case '==': return function() { return this[a] === c;}; break;
case '!=': return function() { return this[a] != c;}; break;
default: return null;
};
}
Assume that i get this function by:
var filterFn = comparator.apply({}, /(.+)(=|>=|<=|<|>|!=|==|!==)(.+)/.exec( "id<4" ).slice(1) );
someModel = someModel.objects.filter( filterFn );
The target it will look:
someModel.get = function( filter ){
return new Model(
this.objects.filter(
comparator.apply({}, /(.+)(=|>=|<=|<|>|!=|==|!==)(.+)/.exec( "id<4" ).slice(1)
)
);
};
var filtered = someModel.get( "id<4" );
Question is - I assume that it will be a lot more operators and I have no idea how to write it more simply.
Using Eval is out of question.
This code didn't was both executed and tested I wrote it just to show what I mean.
Store every function in an object, either pre-defined, or dynamically.
If you want to dyanmically create the set of functions, define the comparator
object as shown below. I assumed that you did not extend the Object.prototype
. If you did, operators.hasOwnProperty(property)
has to be used within the first loop.
// Run only once
var funcs = {}; // Optionally, remove `funcs` and swap `funcs` with `operators`
var operators = { // at the first loop.
'>=': '>=',
'<=': '<=',
'<' : '<',
'>' : '>',
'=' : '==', //!!
'==':'===', //!!
'!=': '!='
}; // Operators
// Function constructor used only once, for construction
for (var operator in operators) {
funcs[operator] = Function('a', 'c',
'return function() {return this[a] ' + operator + ' c};');
}
// Run later
var comparator = function(a, b, c) {
return typeof funcs[b] === 'function' ? funcs[b](a, c) : null;
};
When comparator
is invoked, the returned function looks like:
function() { return this[a] < c; }// Where a, c are pre-determined.
This method can be implemented in this way (demo at JSFiddle):
// Assumed that funcs has been defined
function implementComparator(set, key, operator, value) {
var comparator, newset = [], i;
if (typeof funcs[operator] === 'function') {
comparator = funcs[operator](key, value);
} else { //If the function does not exist...
throw TypeError("Unrecognised operator");
}
// Walk through the whole set
for (i = 0; i < set.length; i++) {
// Invoke the comparator, setting `this` to `set[i]`. If true, push item
if (comparator.call(set[i])) {
newset.push(set[i]);
}
}
return newset;
}
var set = [ {meow: 5}, {meow: 3}, {meow: 4}, {meow: 0}, {meow: 9}]
implementComparator( set , 'meow', '<=', 5);
// equals: [ {meow: 5}, {meow: 3}, {meow: 4}, {meow: 0} ]
For clarification, I constructed this answer, while keeping the following in mind:
Array.prototype.filter
or Array.prototype.sort
.eval
(or Function
) should not be used at every call to comparator
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With