JavaScript
Article

An Introduction to Functional JavaScript

By M. David Green

An Introduction To Functional Javascript

You’ve heard that JavaScript is a functional language, or at least that it’s capable of supporting functional programming. But what is functional programming? And for that matter, if you’re going to start comparing programming paradigms in general, how is a functional approach different from the JavaScript that you’ve always written?

Well, the good news is that JavaScript isn’t picky when it comes to paradigms. You can mix your imperative, object-oriented, prototypal, and functional code as you see fit, and still get the job done. But the bad news is what that means for your code. JavaScript can support a wide range of programming styles simultaneously within the same codebase, so it’s up to you to make the right choices for maintainability, readability, and performance.

Functional JavaScript doesn’t have to take over an entire project in order to add value. Learning a little about the functional approach can help guide some of the decisions you make as you build your projects, regardless of the way you prefer to structure your code. Learning some functional patterns and techniques can put you well on your way to writing cleaner and more elegant JavaScript regardless of your preferred approach.

Imperative JavaScript

JavaScript first gained popularity as an in-browser language, used primarily for adding simple hover and click effects to elements on a web page. For years, that’s most of what people knew about it, and that contributed to the bad reputation JavaScript earned early on.

As developers struggled to match the flexibility of JavaScript against the intricacy of the browser document object model (DOM), actual JavaScript code often looked something like this in the real world:

var result;
function getText() {
  var someText = prompt("Give me something to capitalize");
  capWords(someText);
  alert(result.join(" "));
};
function capWords(input) {
  var counter;
  var inputArray = input.split(" ");
  var transformed = "";
  result = [];
  for (counter = 0; counter < inputArray.length; counter++) {
    transformed = [
      inputArray[counter].charAt(0).toUpperCase(), 
      inputArray[counter].substring(1)
    ].join("");
    result.push(transformed);
  }
};
document.getElementById("main_button").onclick = getText;

So many things are going on in this little snippet of code. Variables are being defined on the global scope. Values are being passed around and modified by functions. DOM methods are being mixed with native JavaScript. The function names are not very descriptive, and that’s due in part to the fact that the whole thing relies on a context that may or may not exist. But if you happened to run this in a browser inside an HTML document that defined a <button id="main_button">, you might get prompted for some text to work with, and then see the an alert with first letter of each of the words in that text capitalized.

Imperative code like this is written to be read and executed from top to bottom (give or take a little variable hoisting). But there are some improvements we could make to clean it up and make it more readable by taking advantage of JavaScript’s object-oriented nature.

Object-Oriented JavaScript

After a few years, developers started to notice the problems with imperative coding in a shared environment like the browser. Global variables from one snippet of JavaScript clobbered global variables set by another. The order in which the code was called affected the results in ways that could be unpredictable, especially given the delays introduced by network connections and rendering times.

Eventually, some better practices emerged to help encapsulate JavaScript code and make it play better with the DOM. An updated variation of the same code above, written to an object-oriented standard, might look something like this:

(function() {
  "use strict";
  var SomeText = function(text) {
    this.text = text;
  };
  SomeText.prototype.capify = function(str) {
    var firstLetter = str.charAt(0);
    var remainder = str.substring(1);
    return [firstLetter.toUpperCase(), remainder].join("");
  };
  SomeText.prototype.capifyWords = function() {
    var result = [];
    var textArray = this.text.split(" ");
    for (var counter = 0; counter < textArray.length; counter++) {
      result.push(this.capify(textArray[counter]));
    }
    return result.join(" ");
  };

  document.getElementById("main_button").addEventListener("click", function(e) {
    var something = prompt("Give me something to capitalize");
    var newText = new SomeText(something);
    alert(newText.capifyWords());
  });
}());

In this object-oriented version, the constructor function simulates a class to model the object we want. Methods live on the new object’s prototype to keep memory use low. And all of the code is isolated in an anonymous immediately-invoked function expression so it doesn’t litter the global scope. There’s even a "use strict" directive to take advantage of the latest JavaScript engine, and the old-fashioned onclick method has been replaced with a shiny new addEventListener, because who uses IE8 or earlier anymore? A script like this would likely be inserted at the end of the <body> element on an HTML document, to make sure all the DOM had been loaded before it was processed so the <button> it relies on would be available.

But despite all this reconfiguration, there are still many artifacts of the same imperative style that led us here. The methods in the constructor function rely on variables that are scoped to the parent object. There’s a looping construct for iterating across all the members of the array of strings. There’s a counter variable that serves no purpose other than to increment the progress through the for loop. And there are methods that produce the side effect of modifying variables that exist outside of their own definitions. All of this makes the code more brittle, less portable, and makes it harder to test the methods outside of this narrow context.

Functional JavaScript

The object-oriented approach is much cleaner and more modular than the imperative approach we started with, but let’s see if we can improve it by addressing some of the drawbacks we discussed. It would be great if we could find ways to take advantage of JavaScript’s built-in ability to treat functions as first-class objects so that our code could be cleaner, more stable, and easier to repurpose.

(function() {
  "use strict";
  var capify = function(str) {
    return [str.charAt(0).toUpperCase(), str.substring(1)].join("");
  };
  var processWords = function(fn, str) {
    return str.split(" ").map(fn).join(" ");
  };
  document.getElementById("main_button").addEventListener("click", function(e) {
    var something = prompt("Give me something to capitalize");
    alert(processWords(capify, something));
  });
}());

Did you notice how much shorter this version is? We’re only defining two functions: capify and processWords. Each of these functions is pure, meaning that they don’t rely on the state of the code they’re called from. The functions don’t create side effects that alter variables outside of themselves. There is one and only one result a function returns for any given set of arguments. Because of these improvements, the new functions are very easy to test, and could be snipped right out of this code and used elsewhere without any modifications.

There might have been one keyword in there that you wouldn’t recognize unless you’ve peeked at some functional code before. We took advantage of the new map method on Array to apply a function to each element of the temporary array we created when we split our string. Map is just one of a handful of convenience methods we were given when modern browsers and server-side JavaScript interpreters implemented the ECMAscript 5 standards. Just using map here, in place of a for loop, eliminated the counter variable and helped make our code much cleaner and easier to read.

Start Thinking Functionally

You don’t have to abandon everything you know to take advantage of the functional paradigm. You can get started thinking about your JavaScript in a functional way by considering a few questions when you write your next program:

  • Are my functions dependent on the context in which they are called, or are they pure and independent?
  • Can I write these functions in such a way that I could depend on them always returning the same result for a given input?
  • Am I sure that my functions don’t modify anything outside of themselves?
  • If I wanted to use these functions in another program, would I need to make changes to them?

This introduction barely scratches the surface of functional JavaScript, but I hope it whets your appetite to learn more.

Meet the author
I've worked as a Web Engineer, Writer, Communications Manager, and Marketing Director at companies such as Apple, Salon.com, StumbleUpon, and Moovweb. My research into the Social Science of Telecommunications at UC Berkeley, and while earning MBA in Organizational Behavior, showed me that the human instinct to network is vital enough to thrive in any medium that allows one person to connect to another.
  • Rick Edwards

    Why not use …

    (function(s){return s.toLowerCase().replace(/bw/g,function(p){return p.toUpperCase()})})(‘function TITLE case’)

    …to return “Function Title Case” ?

  • http://mrjjwright.tumblr.com mrjjwright

    This laid out the imperative versus functional approach really nicely, well done.

  • Zuoliu Ding

    Very good examples and such concise explanations of the concepts to make it clear and well understandable. Thanks

  • stevensokulski

    Great article. Thank you!

    The liink to the MDN is currently pointing to the German docs.

    If you swap /de/ in the url for /en/ it should switch it to English.

    • James Hibbard

      Thanks. Fixed.

  • pertrai1

    Very nice article. I was wondering, as I am starting to get into functional programming, why you say that a pure function is one that does not worry about the state outside itself? I ask because I was reading that pure function was one that had no unused variables. I ask as a novice which could lead me to be asking the question the wrong way.

    • GabrielCTroia

      I believe this is just a matter of semantics. The author refers to it in the context of functional programming (where the function itself doesn’t produce any side effects, thus becomes “pure”), while you are referring to it in a sense closer to what “cohesive” means.

      Here’s an excerpt straight from Uncle Bob on cohesion: “Classes should have a small number of instance variables. Each of the methods of a class should manipulate one or more of those variables. In general the more variables a method manipulates the more cohesive that method is to its class. A class in which each variable is used by each method is maximally cohesive.”

      • mdavidgreen

        Nice explanation of the different issues of cohesion and purity. Thanks for adding that, Gabriel!

    • http://glebbahmutov.com/ Gleb Bahmutov

      Because pure function only works with input arguments and only returns a result – not reading or modifying anything else. Thus you can change everything outside the function – as long as arguments have the same values, the pure function will produce the same returned value

  • Mario

    Yes, your solution will get the “job done” and for a small program might be the way to go. Functional programming is all about decomposing a problem into a set of highly specialized functions that can easily be moved around and reused at different points in the program.

    For example, “processWords” is a higher order function, which makes it very flexible and reusable since the string transformation is handled by the function passed as an argument.

    Great introduction to Functional Programming. Thank you.

    • mdavidgreen

      Nicely put, and thank you. One of the things I love about JavaScript is how versatile it is. There are so many ways to get something done. The artistry is in selecting the approach that is most appropriate to each situation.

      • mbokil

        I completely agree. It is very versatile. If you put in the effort to understand more effective strategies it pays off in more maintainable code and easier debugging.

    • mbokil

      Nice explanation. Getting something done vs. having a reusable piece of code are not the same. In large apps one-offs can eventually bury you in complexity.

  • http://glebbahmutov.com/ Gleb Bahmutov

    Don’t stop there – go all the way to reactive programming http://glebbahmutov.com/blog/journey-from-procedural-to-reactive-javascript-with-stops/

  • https://twitter.com/montecruiseto samir

    For newbies, could you please elaborate in your article on these key points:

    1) “The methods in the constructor function rely on variables that are scoped to the parent object.” (Can you give an example?)

    2) “there are methods that produce the side effect of modifying variables that exist outside of their own definitions” (Can you show exactly what you are talking about by pointing out such a method, variable and how it is modified?)

    cheers!

  • Alexis Reina

    Very nice approach. Just on thing, I tested with a string with all capital letters and the result is the same string, so in your example, in order to work properly I think the capify function should be rewritten as:
    var capify = function(str) {
    return [str.charAt(0).toUpperCase(), str.substring(1).toLowerCase()].join(“”);
    };

  • http://about.me/pakman198 Pako Herrera

    Great article !

  • Greg Nielsen

    Very nice and quick explanations/examples in this article. Thank you!

  • Chris

    Good stuff. Thank you!

  • http://www.wsgeorge.com/ Jesse Jojo Johnson

    Excellent introduction! I’ll bookmark this ;)

  • Kilian Frey

    Wow – very nicely written and concisely explained!

  • Jago Kosolosky ✈

    Loved the article, next step should be this playlist over at YouTube. I admit not everything makes sense but most of it does and I am confident I will understand the rest in a few weeks. https://www.youtube.com/watch?v=BMUiFMZr7vk&list=PL0zVEGEvSaeEd9hlmCXrk5yUyqUag-n84

  • http://dgsprb.github.io/ Diogo

    Having dedicated a great deal of my time to the OOP paradigm in JS (as of http://dgsprb.github.io/JavaScriptwithClasses.pdf) I have had a hard time fitting functional JS to my needs. This arcticle broke that barrier and now I got really interested in learning more about it. Thank you for that!

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in JavaScript, once a week, for free.