by Logo Technical Blog – Future Processing
22.12.2014
Javascript – functional programming and lambdas_

Let’s imagine that we have to do two simple things in JavaScript:
1. Check whether all elements in a table have a specific value
2. Filter a table

Standard approach

1)

var tab = [ 1, 1, 1];
var allTheSame = true;
for(var i in tab) {
   if (tab[i] !== 1) {
   allTheSame = false;
   break;
}
};
console.log(allTheSame); // true

2)

var tab = [ 1, 1, 2];
var filtered = [];
for(var i in tab) {
   if (tab[i] > 1) {
   filtered.push(tab[i]);
}
};
console.log(filtered); // [2]

It seems to be ok,but what can be improved?

Improvement 1 – built-in functions

ECMAScript 5 got new functionalities for tables such as every, some, forEach, map, filter, reduce
They are supported by all new browsers (IE>=9) http://kangax.github.io/compat-table/es5/
Now, our examples are as follows:

1)

var tab = [ 1, 1, 1];
var allTheSame = tab.every(function(el) {
   return el === 1;
});
console.log(allTheSame);

2) filtering

var filtered = tab.filter(function(el) {
   return el > 1;
});
console.log(filtered); // [2]

Improvement 2 – different libraries

If we want to support older browser or we want to have more opportunities we can take advantage from free libraries.

a) jQuery – has basic functionalities such as. .grep (filter), .each, .map, .is. Some of them are improved relative to those of ECMAScript 5, e.g. we can left .each using the return false, whereas we can also filter in the .map.
Record $.grep(tab, function(el, i) {} ) or $(tab).each(function(i, el) { })

b) Underscorehttp://underscorejs.org/
Known library. Huge opportunities.
Here, you can find exemplary functions I used: findWhere (searching among objects), groupBy, sortBy, contains, isEmpty, pluck. We can form chains e.g.

_.chain(stooges)
.sortBy(function(stooge){ return stooge.age; })
.map(function(stooge){ return stooge.name + ' is ' + stooge.age; })
.first()
.value();

c) Lo-Dash – slightly improved clone of underscore
d) other
functional.js: http://functionaljs.com/
e.g.

fjs.every(function (item) {
   return item % 2 === 0;
})([1,2,3]);

Rambda: http://ramda.github.io/ramdocs/docs/R.html#gt
e.g.

var double = function(x) {
   return x * 2;
};
R.map(double, [1, 2, 3]); //=> [2, 4, 6]

linq.js: http://linqjs.codeplex.com/ – almost 1:1 with Linq with .net
e.g.

Enumerable.Range(1, 10)
.Where(function(i) { return i % 3 == 0; })
.Select(function(i) { return i * 10; })

Improvement 3 – auxiliary functions

To code was even shorter and easier to read, we can add auxiliary functions to compare values.
e.g.

var eq = function(valueToCompare) {
   return function(valueInList) {
      return valueInList === valueToCompare;
};
};

And now, instead of

var allTheSame = tab.every(function(el) {
   return el === 1;
});

we can write

var allTheSame = tab.every(eq(1));

Of course, we can add much more functions, such as gt, notEmpty, and, or etc.
We can also use library e.g.
f_underscore.js: http://krisjordan.github.io/f_underscore/#
e.g.

_.map(stooges, f_.toUpperCase(f_.get('name')));

Improvement 4 – lambdas

If you like lambdas, they are supported by libraries:
a) functional.js: http://functionaljs.com/basics/lambda/
e.g.

var doubleMap = fjs.map("n => n * 2");

b) linq.js
e.g.

var queryResult2 = Enumerable.From(jsonArray)
.Where("$.user.id < 200")
.OrderBy("$.user.screen_name")
.Select("$.user.screen_name + ':' + $.text")
.ToArray();

c) lambda.jshttp://www.javascriptoo.com/lambda-js/
I add lambda function that takes a string and returns a function so that you can use it practically everywhere e.g.

var allTheSame = tab.every(lambda("== 1"));

of course, you can add something shorter than lambda
e.g.

L tab.every(L("== 1");

You can even extend the built-in functions to accept lambdas

["filter", "some", "every", "map"].forEach(function(fnName) {
    var oldF = Array.prototype[fnName];    
    Array.prototype[fnName] = function(fun) {
        var args = Array.prototype.slice.call(arguments);
        if (typeof fun == "string") {        
            args[0] = lambda(fun);
        }
    return oldF.apply(this, args);
};
});

If the first argument is a string, we change it to function using lambda.js library and pass it on.

And now we can do this:

[1,2,3].filter("> 1").map("x-> {key: x + 1}") //[{key: 3}, {key: 4}]

It couldn’t be simpler 🙂

Related Posts

Comments

Cookies

This website stores cookies on your computer. These cookies are used to improve our website and provide more personalized services to you, both on this website and through other media. To find out more about the cookies we use, see our Cookies policy.