JavaScript as a Functional Language

Tagged:  

Douglas Crockford, author of the JSON data format, has written that JavaScript as a language is like a "Lisp in C's clothing":

JavaScript's C-like syntax, including curly braces and the clunky for statement, makes it appear to be an ordinary procedural language. This is misleading because JavaScript has more in common with functional languages like Lisp or Scheme than with C or Java.

This is a really interesting statement, especially if you are used to looking at JavaScript code like this:

var myGlobal = ...;
function myProceduralFunction() {
     // ...
}

Don't laugh...you've probably written JavaScript like this at one time or another. I certainly did, before I really understood JavaScript. For a long time, this is how most people grokked JavaScript, as a kind of dynamically typed C/C++. There are also those who try to make JavaScript behave as a Java-style OOP language (a natural tendency, given the misnomer): using nested objects as package-style "namespaces", trying to make prototypical inheritance look like static class inheritance, etc. It's all a bit of a stretch, but since JavaScript does actually borrow many OOP concepts, it can be done. I would argue, though, that Crockford is right and JavaScript is more naturally used as a functional language. In this article I am going to briefly examine some of the similarities between JavaScript and functional programming languages, and how the JavaScript programmer can use them to his/her advantage.

First-Class Functions

One of the most important and primary concepts in functional programming is that of code as data. What does this mean? Well, in most imperative languages, there is a distinction between data, the values that exist at a given place in memory, and programs, the set of processor instructions that manipulate the data. It's a natural thing to do, given the design of the Von Neumann architecture. In functional programming, this distinction is blurred: functions themselves are thought of as data, which can be passed around, returned from other functions, and manipulated directly.

Specifically, a language that supports first-class functions means:

  1. Functions (and anonymous functions or lambdas) can be created during the execution of a program.
  2. Functions can be passed in as arguments to other functions.
  3. Functions can returned from other functions as return values.
  4. Functions be assigned to variables (stored in data structures, etc.).

Of course, JavaScript can do all of these things:

// #1 and #2
obj.doSomething("Passing callback", function() {
     //callback here
});

// #1 and #3
function getCounter() {
     var i=0;
     return function() { ++i; };
}

// #1 and #4
var data = {
     n: 10, 
     fn: function() { ... }
}

Figure 1: First-class functions in JavaScript

First-class functions are the feature that enables everything else in functional programming. Once you have it, most other functional programming language features fall right into place.

Higher-Order Functions

Closely related to the concept of first-class functions, higher-order functions are functions that take in one or more functions as arguments and/or return a function as a return value. The most common example from mathematics would be the derivative from calculus. The doSomething() and getCounter() in Figure 1 above would both be examples of higher-order functions.

Higher-order functions allow us to do functional composition, which would be familiar to any Lisp programmer:

// math notation: f(g(x))
function compose(f, g) {
     return function(x) {
          return f(g(x));
     }
}

Currying

Higher-order functions also enable currying, which transforms a function that has multiple arguments into a function which takes less arguments by fixing the value of one or more of its arguments (actually, technically speaking, currying transforms the function into a chain of functions, each of which takes a single argument, but the term is used loosely). Let's do this in JavaScript:

// first arg is function, and the rest (undeclared) 
// are arguments to that function
function curry(func) {
   var fixedArgs = Array.prototype.slice.call(arguments).slice(1);
   //returns closure that is a curried function
   return function() {
      var localArgs = Array.prototype.slice.call(arguments);
      return func.apply(null, localArgs.concat(fixedArgs));
   }
}

// our test function
function add(x, y) {
     return x + y;
}

// now let's use it
var plusFive = curry(add, 5);
var result = plusFive(2);  // => 7

(The Array.prototype.slice.call here is a hack to get around the fact that arguments is not an actual Array object in JavaScript.) Since JavaScript does not have "overloaded" functions, this type of functionality is usually simulated using manipulation of the function's arguments. Currying comes in handy because it allows you to do this manipulation in a much cleaner and more modular way.

Currying is also a good example of the continuation passing style, a method of passing control via a continuation (here represented as a function). CPS forms the basis for the concept of monads, a more powerful concept that is used heavily in languages like Haskell.

Closures

As any Rubyist will tell you, closures are a powerful programming language feature. Often confused with anonymous functions (not really the same thing conceptually, though they are often seen hanging out together), closures are functions that can execute outside of the environment in which they were created, while holding references to bound variables from that environment. A good example of this is the getCounter() example from Figure 1, which returns a closure that binds the variable i. What happens if we call this function and then invoke the returned closure?

var increment = getCounter();
increment();    // => 1
increment();    // => 2
increment();    // => 3

Closures have quite a few applications in real-world JavaScript: event binding, callbacks, sorting, mapping (in the classical Lisp sense), and many others. In more modern JavaScript programming, you can find them almost everywhere.

One of the most interesting uses of a closure is compensating for the lack of built-in namespaces in JavaScript. For example, if you look at the source code for jQuery, you will a code structure looking something like this:

(function() {
   var jQuery=window.jQuery=window.$=function(selector,context)  {
          // ...
   }
}) ();

So what's happening here? Well, jQuery is wrapping the entire body of its code in an anonymous function, and then invoking it. Because the function is a closure, it automatically captures its surrounding context, but hides its own code from the global namespace. In order to give the user of the library a handle to it, the "jQuery" and "$" names are put back into the global namespace by adding them to the window object. Hence closures can be used to do encapsulation, and it is this functionality that allows you to have "private" variables in JavaScript.

Conclusion

Of course, there is a little bit of hand-waving involved in calling JavaScript a functional language. JavaScript is not a side-effect free language, nor is it an expression-based language (i.e., it is not value-oriented, but rather variable-oriented). There is no tail call optimization in any of the current implementations, so recursion must be kept shallow. And the list goes on.

Truth be told, JavaScript is really one of the first hybrid imperative-functional languages. Given the awkwardness of making it behave in a traditionally OOP fashion and the primary position occupied by the function type, it often works better as a functional language than in any other way. And this is actually a good thing because it allows the JavaScript programmer to use some of the more powerful paradigms that are available in functional programming. Case in point: jQuery, which fully exploits the "LISP 1" nature of JavaScript:

  • What are always returned by jQuery selectors? Lists of elements. jQuery focuses on list processing, as does LISP.
  • Most operations in jQuery are really mapping functions to a list (of selected elements), which is absolutely idiomatic LISP.
  • The "method chaining" so beloved by jQuery users is really the Continuation Passing Style in disguise.

I highly recommend learning functional programming to any programmer (not just those wishing to be JavaScript gurus). Even if you never use it in your day job, the experience of truly thinking in a functional way may just change the way you think about programming.

Resources

1. The online course Functional Programming, a U.C. Berkeley webcast.
2. Any number of LISP tutorials (the Scheme dialect is probably the easiest to learn).
3. If you're a Java guy/gal, you may want to try Clojure, a LISP dialect that is one of the few languages with built-in software transactional memory. It's also a really small download (less than 2 MB). It's written in Java, so it's very portable and inter-operates well with the thousands of existing Java libraries.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <pre> <div> <blockquote> <object> <embed> <img> <param>
  • Lines and paragraphs break automatically.
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Copy the characters (respecting upper/lower case) from the image.