liveBook · Manning

Data transformation

As explained in The Joy of JavaScript

A map is a function or method that applies a transformation to each element or value in a structure and returns a corresponding structure.

`map` applies a function to each value in a structure and returns a corresponding structure. With an array, it transforms elements without changing the original array. With a composable object or observable, the same idea transforms a contained value or an emitted event while preserving the kind of structure. section 4.1 section 5.4 section 9.4.3

From loops to a data pipeline

A wallet balance can be calculated by filtering out genesis blocks, extracting their transactions, mapping each transaction to its effect on one address, and reducing those effects to a total. `flatMap(prop('data'))` can replace a separate `map(prop('data')).flat()` when transaction arrays must be flattened. The pipeline makes the data explicit rather than repeatedly changing a balance inside nested loops. section 4.7

Mapping is a form of composition: each transformation supplies a value to the next. A curried `map` can be used inside `compose`, while an object’s `map` method provides a similar way to chain transformations. `flatMap` serves a different need: it chains functions that themselves return a structure, such as validation checks returning `Validation` results. section 4.7 section 5.3 section 5.5.5

Transforming a validated value

A `Success` value can be mapped through a calculation and remain a `Success`: `map.call(Success.of(2), x => x * 2)` yields `Success(4)`. A shared map contract also lets standalone library functions delegate to an object’s own `map` method. section 5.6 section 5.5.8

Listing 9.18 Custom map operator
const map = curry(                                  #1
    (fn, stream) =>
        new Observable(observer => {                #2
            const subs = stream.subscribe({         #3
               next(value) {
                  try {
                     observer.next(fn(value));      #4
                  }
                  catch (err) {
                     observer.error(err);
                  }
               },
               error(e) {
                  observer.error(e);                #5
               },
               complete() {
                  observer.complete();              #6
               }
        });
        return () => subs.unsubscribe();            #7
    });
);

An observable map subscribes to its source and sends `fn(value)` downstream as each value arrives. It also forwards errors and completion and provides an unsubscribe path, so mapping remains part of a composable event pipeline. section 9.4.3

How The Joy of JavaScript covers it

How deep it goes
Works through array pipelines, the map/compose correspondence, shared object contracts, and an observable operator implementation; leaves full ADT theory aside.
Examples
Uses block validation, wallet-balance calculation, mapped Success values, and a number-sequence observable.
What it assumes
Assumes familiarity with JavaScript callbacks and array APIs, while introducing composable object interfaces through examples.
What you can do after
Build it from scratch as an observable operator, or apply it to compose array and object transformations.
How it connects
Connects map to higher-order functions, immutability, function composition, functors, flatMap, validation, and observables.

Also explained in

Compare how 20 books explain data transformation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Joy of JavaScript. The section links point to the parts of the book it draws on.