Functionalism w/ Underscore.js

Here we use the underscore.js javascript library to explore code changes from traditional, procedural solutions to functional chaining solutions.

by maxisam

HTML

<script src="http://www.gridlinked.info/cdn/js/underscore-min.js"></script>
<script src="http://www.gridlinked.info/cdn/highlighter/head.load.min.js"></script>
<script src="http://www.gridlinked.info/cdn/highlighter/head_highlighter.js"></script>
<link rel="stylesheet" href="http://www.gridlinked.info/cdn/css/jsFiddle_embed.css">
<body>

<div id="body">
    <div id="header"></div>
    <div id="contents">
        <div id="intro">
            <p>                
                Functional programming with <strong><a href="http://documentcloud.github.com/underscore/" target="_blank">Underscore.js</a></strong>.      
            </p>
        </div>
        <h2><code><span class='code'>Scenario</span></code></h2>
        <br/>
        <div class="contents">
            <div class="bullet">
                <div class="description">
                    Let's explore the migration from <span class="underline">traditional</span> to <span class="underline">functional</span> 
                    approaches to implement a solution to an easy programmatic challenge. Consider the objective below:

                    <ul> 
                        <li>Convert a list of names to instances of People objects</li>
                        <li>Ask each person to speak</li>
                    </ul>
                    <br/>
                    The code samples in this tutorial will all use a factory method <code><span class='code'>buildPerson()</span></code> to build a Person object:
                    
                    <pre class="brush: js;">
                    function buildPerson(name, target) {            
                        return {
                            speak: function(where) {
                                if ( !where ) where = target;
                                
                                var words = 'Hello, my name is <span class="answer">{0}</span><br/>';
                                where.append( supplant(words, [name]) );                   ...

JavaScript

(function(_, $) {
    // http://skilldrick.co.uk/2011/07/easy-functional-programming-in-javascript-with-underscore-js-part-1/comment-page-1/#comment-9919

    function logTitle(title, target) {
        if (!target) { target = $("body"); }
        var format = "<span class='title'><br/> {0}: <br/></span>";
        target.append(supplant(format, [title]));
    }

    function logAnswer(answer, target) {
        if (!target) { target = $("body"); }
        var format = "Hello, my name is <span class='answer'>{0}</span><br/>";
        target.append(supplant(format, [answer]));
    }


    // supplant() method from Crockfords `Remedial Javascript`


    function supplant(template, values, pattern) {
        pattern = pattern || /\{([^\{\}]*)\}/g;

        return template.replace(pattern, function(a, b) {
            var p = b.split('.'),
                r = values;

            try {
                for (var s in p) {
                    r = r[p[s]];
                };
            } catch (e) {
                r = a;
            }

            return (typeof r === 'string' || typeof r === 'number') ? r : a;
        });
    };

    // Return Cat object with `speak` ability


    function buildPerson(name) {
        return {
            speak: function(target) {
                logAnswer(name, target);
            }
        };
    }

    // ****************************************************************

    // Traditional Approach
    $("#runSolution1").one("click", function() {
        var names = ['Thomas Burleson', 'John Yanarella', 'Indiver Nagpal'];
        var people = [];

        for (var i = 0, len = names.length; i < len; i++) {
            people.push(buildPerson(names[i]));
        }

        $("#outputSolution1").html("");

        for (var i = 0, len = people.length; i < len; i++) {
            people[i].speak($("#outputSolution1"));
        }
        $("#runSolution1").hide();
    });

    // Let's use underscore.js library API:  map() and each()
    //...