I use a lot of lambda expressions in C#, so I've decided to create some similar functionality in JavaScript. Since jQuery is included in my projects, I'm using $.grep() instead of Array.prototype.filter() to support older browsers without including shims.
The two examples below corresponds to Where() and FirstOrDefault() in C#:
if(!Array.prototype.where){
Array.prototype.where = function (func) {
var that = this;
switch (typeof func) {
case 'function':
return $.grep(that, func);
case 'object':
for(var prop in func){
that = $.grep(that, function(item){
return item[prop] === func[prop];
});
}
return that;
default:
throw new ReferenceError("no/wrong func type passed");
}
};
}
if(!Array.prototype.firstOrDefault){
Array.prototype.firstOrDefault = function(func){
return this.where(func)[0] || null;
};
}
var persons = [{ name: 'foo', age: 1 }, { name: 'bar', age: 2 }];
var where1 = persons.where(function(p){
return p.age === 1 && p.name === 'foo';
});
console.log(where1);
var where2 = persons.where({ age: 1, name: 'foo' });
console.log(where2);
var fod1 = persons.firstOrDefault(function(p){
return p.age === 1 && p.name === 'foo';
});
console.log(fod1);
var fod2 = persons.firstOrDefault({ age: 1, name: 'foo' });
console.log(fod2);
I would have preferred to add the methods as non-enumerable using Object.defineProperty, but since I need to support IE >= 7, that's not an option.
However, the only downside with having the methods enumerable would be if someone is iterating an array using for..in, which they shouldn't do in the fist place.
In case of an object being passed as argument, one way to decrease the total iterations from array length * object property count to array length * 1 could be solved using the function constructor:
var o = { foo: 1, bar: true, s: 's' };
var str = Object.keys(o).reduce(function (prev, key) {
if(typeof o[key] === 'string')
o[key] = '\'' + o[key] + '\'';
return (prev ? prev + ' && ' : '') + 'x.' + key + ' === ' + o[key];
}, '');
var f = new Function('x', 'return ' + str + ';');
// pass f to filter/$.grep
console.log(f);
I would like some feedback about possible performance improvements and what you think about the code in general (but not pros and cons with extending native objects).