Functional Programmingusing Underscore.js
othree @ OSDC 2013
me
• @othree
• https://blog.othree.net
me
• PhD Candidate
• Front End Engineer
• On the way learning good from functional programming languages
Function ofFunctional Language
• Pure function
• First class citizen
• Higher order function
• ...
Pure Function
• Side effect free
• Same input, same output
• ex: trigonometric functions
First Class Citizen
• Function like variable
• ex: function expression
var f = function () { /*...*/ };
Higher Order Function
• Function takes or return functions
• ex: event listener
http://www.flickr.com/photos/78428166@N00/6036104277/
Take a LookExamples from ‘Pure, functional JavaScript’
http://cjohansen.no/talks/2012/sdc-functional/
[ { name: 'Gates', gender: 'M', org: 'M$' }, { name: 'Peter' gender: 'M', org: 'Hㄒㄈ' }]
"Mentioned by Gates, Peter, Jobs"
var str = "Mentioned by ";
for (var i = 0, l = tweeps.length; i < l; ++i) { str += tweeps[i].name; if (i < tweeps.length - 1) { str += ", "; }}
[ { name: 'Gates', gender: 'M', org: 'M$' }, { name: 'Peter' gender: 'M', org: 'Hㄒㄈ' }]
[ 'Gates', 'Peter']
var names = [];
for (var i = 0, l = tweeps.length; i < l; ++i) { names.push(tweeps[i].name);}
var str = "Mentioned by " + names.join(", ");
var names = tweeps.map(function (tweep) { return tweep.name;});
var names = tweeps.map(function (t) { return t.name; });
var str = "Mentioned by " + tweeps.map(function (t) { return t.name;}).join(", ");
function prop(name) { return function (object) { return object[name]; };}
var str = "Mentioned by " + tweeps.map(prop("name")).join(", ");
Case 2
[ { getSummary: function () { return { text: 'Summaries', html: '<p>Summaries</p>' }; } }, { getSummary: function () { return {text: 'Summaried'}; } }, ...]
<div> <p>Summaries</p> <p>Summaried</p> <p>Summary</p></div>
buildSummary: function () { var div = document.createElement("div"), p;
for (var i = 0, l = this.components.length; i < l; ++i) { p = document.createElement("p"); p.innerHTML = this.components[i].getSummary().text; div.appendChild(p); }
return div;}
DOM functions
var ul = cull.dom.el("ul");ul.nodeType === 1 // true
https://github.com/culljs/dome/
var ul = cull.dom.el("ul", { className: "bands" });
//var li = cull.dom.el("li", "Execration");var ul = cull.dom.el("ul", { className: "bands" }, li);
var ul = cull.partial(cull.dom.el, "ul");var li = cull.partial(cull.dom.el, "li");
["a", "br", "code", "div", ...].forEach(function (tagName) { cull.dom.el[tagName] = cull.partial(cull.dom.el, tagName);});
//["a", "br", "code", "div", ...].forEach(function (tagName) { root[tagName] = cull.partial(cull.dom.el, tagName);});
http://www.flickr.com/photos/jackhynes/519904699/
buildSummary: function () { return div(this.components.map(function (component) { return p(component.getSummary().text); }));}
buildSummary: function () { return div(this.components.map(function (component) { return p(component.getSummary().text); }));} 1
buildSummary: function () { return div(this.components.map(function (component) { return p(component.getSummary().text); }));} 1 2
buildSummary: function () { return div(this.components.map(function (component) { return p(component.getSummary().text); }));} 1 23
buildSummary: function () { return div(this.components. map(function (component) { return component.getSummary(); }).map(function (summary) { return summary.text; }).map(function (text) { return p(text); }));}
function func(name) { return function (object) { return object[name](); };}
buildSummary: function () { return div(this.components. map(func("getSummary")). map(function (summary) { return summary.text; }).map(function (text) { return p(text); }));}
buildSummary: function () { return div(this.components. map(func("getSummary")). map(prop("text")). map(function (text) { return p(text); }));}
buildSummary: function () { return div(this.components. map(func("getSummary")). map(prop("text")). map(p));}
var summarize = compose([p, prop("text"), func("getSummary")]);
var callGetSummary = func("getSummary");var getText = prop("text");var summarize = compose([p, getText, callGetSummary]);
// summarize(obj);// => callGetSummary(obj)// => getText(callGetSummary(obj))// => p(getText(callGetSummary(obj)))
buildSummary: function () { var summarize = compose([p, prop("text"), func("getSummary")]); return div(this.components.map(summarize));}
var summarize = compose([p, prop("text"), func("getSummary")]);
// ...
buildSummary: function () { return div(this.components.map(summarize));}
http://www.flickr.com/photos/guerson/5630633727/
Functional Programming in JavaScript
Native
• forEach
• map/reduce
• filter
Functional JavaScript
• by Oliver Steele at 2007
• First functional JavaScript Library I know
Underscore.js
• by Jeremy Ashkenas from DocumentCloud
• “Underscore is a utility-belt library for JavaScript that provides a lot of the functional programming support”
Lo-Dash
• Will talk later
cull.js
• by Christian Johansen and Magnar Sveen
• “Cull is a toolbelt for writing functional javascript.”
• Used in the examples above
https://github.com/culljs/culljs
LiveScript & prelude.ls
• by George Zahariev
• A new compile to JavaScript language fork from Coco
• Stay in this room until tomorrow, Mindos have a talk about LiveScript
GHCJS
• by Hamish Mackenzie, Victor Nazarov, Luite Stegeman
• Haskell to JavaScript compiler
Underscore.js
• compose
• map/reduce
• filter
• pluck
var str = "Mentioned by " + tweeps.map(prop("name")).join(", ");
var str = "Mentioned by " + _.reduce( _.map(tweeps, function (t) { return t.name; }), function (memo, name, i) { return (i == 0) ? name : memo + ', ' + name; }, '');
var str = "Mentioned by " + _(tweeps) .chain() .map(function (t) { return t.name; }) .reduce(function (memo, name, i) { return (i == 0) ? name : memo + ', ' + name; }, '') .value();
var str = "Mentioned by " + _(tweeps) .map(function (t) { return t.name; }) .join(', ');
var str = "Mentioned by " + _(tweeps).pluck('name').join(', ');
Still Not Enough
• curry, partial
• prop, func from above example
Lo-Dash
Functional Programmingusing Underscore.js
othree @ OSDC 2013.1
Functional Programmingusing Underscore.jsLo-Dash
othree @ OSDC 2013.1
-
_
_-
_-
What is Lo-Dash
• Underscore.js fork by John-David Dalton, Kit Cambridge, and Mathias Bynens
Difference
• Better performance
• Robust result
• Larger file size
• AMD supports
• Auto chain
• More power: cloneDeep, partial, result...
_.partial
var greet = function(greeting, name) { return greeting + ' ' + name; };var hi = _.partial(greet, 'hi');hi('moe');// ! 'hi moe'
http://lodash.com/docs#partial
_.result
var object = { 'cheese': 'crumpets', 'stuff': function () { return 'nonsense'; }};
_.result(object, 'cheese');// ! 'crumpets'
_.result(object, 'stuff');// ! 'nonsense'
http://lodash.com/docs#result
With Lo-Dash
var summarize = compose([p, prop("text"), func("getSummary")]);
// ...
buildSummary: function () { return div(map(summarize), this.components);}
var summarize = _.compose( p, _.partialRight(_.result, 'name'), _.partialRight(_.result, 'getSummary') );
// ...
buildSummary: function () { return div(_.map(this.components, summarize));}
Performance?
Bad..
http://jsperf.com/for-vs-foreach/71
http://jsperf.com/for-vs-foreach/71
• Take benefits from functional programming
• Not change everything to functional
• Library helps, ex: lo-dash
ReferencesFurther Readings
http://interglacial.com/hoj/hoj.html
http://cjohansen.no/talks/2012/sdc-functional/
http://kitcambridge.be/blog/say-hello-to-lo-dash/
http://www.slideshare.net/ihower/fp-osdc2012v2
http://shop.oreilly.com/product/9781593272821.do
http://shop.oreilly.com/product/0636920028857.do
http://shop.oreilly.com/product/0636920028857.do
Not
Yet
Rel
ease
d
Questions?
http://www.flickr.com/photos/roman/5610736/