Searching...
English
English
Español
简体中文
Français
Deutsch
日本語
Português
Italiano
한국어
Русский
Nederlands
العربية
Polski
हिन्दी
Tiếng Việt
Svenska
Ελληνικά
Türkçe
ไทย
Čeština
Română
Magyar
Українська
Bahasa Indonesia
Dansk
Suomi
Български
עברית
Norsk
Hrvatski
Català
Slovenčina
Lietuvių
Slovenščina
Српски
Eesti
Latviešu
فارسی
മലയാളം
தமிழ்
اردو
Functional JavaScript

Functional JavaScript

Introducing Functional Programming with Underscore.js
by Michael Fogus 2013 258 pages
Programming
Technology
Computer Science
Listen
8 minutes

Key Takeaways

1. JavaScript supports functional programming through first-class functions

A first-class function is one that can go anywhere that any other value can go—there are few to no restrictions.

Functions as values. In JavaScript, functions can be assigned to variables, passed as arguments to other functions, returned from functions, and stored in data structures. This flexibility enables functional programming techniques. For example:

  • Assigning a function to a variable: var square = function(x) { return x * x; }
  • Passing a function as an argument: [1, 2, 3].map(function(x) { return x * 2; })
  • Returning a function: function makeAdder(x) { return function(y) { return x + y; }; }

This first-class nature of functions is the foundation for many functional programming patterns in JavaScript.

2. Higher-order functions are key to functional JavaScript

Higher-order functions that capture other functions are a very powerful technique for building abstractions.

Powerful abstractions. Higher-order functions either take functions as arguments or return functions as results. They enable powerful abstractions and code reuse. Common examples include:

  • map: Transform each element in a collection
  • reduce: Combine elements of a collection into a single value
  • filter: Select elements from a collection based on a predicate

These functions allow you to express complex operations succinctly and compose behavior. For instance:

const numbers = [1, 2, 3, 4, 5];
const evenSquares = numbers
  .filter(x => x % 2 === 0)
  .map(x => x * x);

This code clearly expresses the intent of selecting even numbers and squaring them, without explicitly managing loops or intermediate arrays.

3. Closures enable powerful functional techniques in JavaScript

A closure is a function that captures the external bindings (i.e., not its own arguments) contained in the scope in which it was defined for later use (even after that scope has completed).

Encapsulation and state. Closures allow functions to "remember" and access variables from their outer scope, even after that scope has finished executing. This enables:

  • Private state: Create variables that are accessible only through specific functions
  • Function factories: Generate specialized functions based on parameters
  • Partial application: Create new functions by fixing some arguments of existing functions

Example of a closure maintaining private state:

function counter() {
  let count = 0;
  return function() {
    return ++count;
  };
}

const increment = counter();
increment(); // 1
increment(); // 2

The count variable is not directly accessible, but the returned function can access and modify it.

4. Function composition allows building complex behaviors from simple parts

Functional programming is about pulling programs apart and reassembling them from the same parts, abstracted behind function boundaries.

Building complexity. Function composition is the process of combining two or more functions to create a new function. This allows you to:

  • Create complex behaviors from simple, reusable parts
  • Improve code readability by breaking down complex operations
  • Enhance maintainability by isolating and testing smaller units of functionality

Composition can be achieved through various means:

  • Manual composition: const f = x => h(g(x))
  • Utility functions: const compose = (f, g) => x => f(g(x))
  • Libraries like Ramda or Lodash/FP

Example of building a data processing pipeline through composition:

const processData = compose(
  summarize,
  filterOutliers,
  normalize,
  parseInput
);

This clearly expresses the steps of data processing without cluttering the code with implementation details.

5. Pure functions and immutability lead to more predictable code

Programming with pure functions may seem incredibly limiting. [...] However, when you exercise a libertarian view of state mutation, you're actually limiting your possibilities in composition, complicating your ability to reason through the effects of any given statement, and making it more difficult to test your code.

Predictability and testability. Pure functions always produce the same output for given inputs and have no side effects. This, combined with immutable data:

  • Simplifies reasoning about code behavior
  • Facilitates easier testing and debugging
  • Enables safe parallelization and memoization

Strategies for maintaining purity and immutability:

  • Use const for variables that shouldn't change
  • Create new objects/arrays instead of modifying existing ones
  • Employ libraries like Immutable.js for efficient immutable data structures

Example of a pure function:

function addToCart(cart, item) {
  return [...cart, item];
}

This function doesn't modify the original cart, making it easier to track changes and predict behavior.

6. Recursion provides an alternative to loops in functional programming

Using recursion, state is managed via the function arguments, and change is modeled via the arguments from one recursive call to the next.

Elegant solutions. Recursion often leads to more elegant and concise solutions for problems involving hierarchical or repetitive structures. Benefits include:

  • Natural expression of some algorithms (e.g., tree traversal)
  • Avoidance of mutable state often associated with loops
  • Potential for compiler optimizations (tail-call optimization)

However, be aware of stack overflow risks in JavaScript, which lacks tail-call optimization in most environments. Techniques to mitigate this include:

  • Trampolining: Wrapping recursive calls in thunks
  • Continuation-passing style: Explicitly managing the call stack

Example of a recursive function to flatten a nested array:

function flatten(arr) {
  return arr.reduce((flat, next) => 
    flat.concat(Array.isArray(next) ? flatten(next) : next), 
  []);
}

7. Functional programming facilitates data flow and transformation pipelines

Pipelines are meant to be pure—no data was harmed by running it through.

Clear data transformations. Functional programming encourages thinking in terms of data flowing through a series of transformations. This approach:

  • Improves code readability by clearly showing the steps of data processing
  • Enhances maintainability by separating concerns
  • Facilitates parallelization and optimization

Techniques for building pipelines:

  • Method chaining (e.g., with lodash)
  • Composition of pure functions
  • Specialized libraries like RxJS for asynchronous data streams

Example of a data processing pipeline:

const processOrders = pipe(
  fetchOrders,
  filterValidOrders,
  calculateTotals,
  generateReport
);

This clearly shows the steps involved in processing orders without getting bogged down in implementation details.

8. Mixin-based design offers a functional approach to object composition

Simple data is best. Specialized data types should be, well, special.

Flexible composition. Mixins provide a way to compose object behavior without relying on classical inheritance. This approach:

  • Allows for more flexible and modular code design
  • Avoids problems associated with deep inheritance hierarchies
  • Facilitates a more functional style of object-oriented programming

Implementing mixins in JavaScript:

  • Use Object.assign() to copy methods onto object prototypes
  • Employ higher-order functions to create factory functions that apply mixins

Example of creating an object with mixins:

const withLogging = (obj) => ({
  ...obj,
  log: (msg) => console.log(`[${obj.name}]: ${msg}`)
});

const withValidator = (obj) => ({
  ...obj,
  validate: () => { /* validation logic */ }
});

const createUser = (name) => 
  withValidator(withLogging({ name, data: {} }));

This approach allows for flexible composition of object behavior without rigid class hierarchies.

Last updated:

Review Summary

4.07 out of 5
Average of 100+ ratings from Goodreads and Amazon.

Functional JavaScript receives mostly positive reviews, with an average rating of 4.07 out of 5. Readers appreciate its clear explanation of functional programming concepts in JavaScript, praising its straightforward approach and practical examples. Many find it eye-opening and valuable for improving their coding skills. Some reviewers note its density and recommend it for intermediate to advanced programmers. While a few criticize its reliance on Underscore.js and question its real-world applicability, most agree it's a solid introduction to functional programming techniques in JavaScript.

About the Author

Michael Fogus is an experienced software developer and author known for his expertise in functional programming. He has written multiple books on programming, including "The Joy of Clojure" and "Functional JavaScript." Fogus is respected for his ability to explain complex concepts clearly and concisely. His work often focuses on applying functional programming principles to various languages, particularly JavaScript. Fogus is also known for his contributions to the Clojure community and his involvement in developing programming languages. His writing style is praised for being straightforward and enlightening, making difficult topics accessible to readers with varying levels of experience.

0:00
-0:00
1x
Create a free account to unlock:
Bookmarks – save your favorite books
History – revisit books later
Ratings – rate books & see your ratings
Listening – audio summariesListen to the first takeaway of every book for free, upgrade to Pro for unlimited listening.
Unlock unlimited listening
Your first week's on us!
Today: Get Instant Access
Listen to full summaries of 73,530 books. That's 12,000+ hours of audio!
Day 5: Trial Reminder
We'll send you a notification that your trial is ending soon.
Day 7: Your subscription begins
You'll be charged on Sep 29,
cancel anytime before.
Compare Features Free Pro
Read full text summaries
Summaries are free to read for everyone
Listen to full summaries
Free users can listen to the first takeaway only
Unlimited Bookmarks
Free users are limited to 10
Unlimited History
Free users are limited to 10
What our users say
15,000+ readers
“...I can 10x the number of books I can read...”
“...exceptionally accurate, engaging, and beautifully presented...”
“...better than any amazon review when I'm making a book-buying decision...”
Save 62%
Yearly
$119.88 $44.99/yr
$3.75/mo
Monthly
$9.99/mo
Try Free & Unlock
7 days free, then $44.99/year. Cancel anytime.