Smooshing JavaScript

K - Mar 11 '18 - - Dev Community

Cover image by David on Flickr, cropped by me.

As a JavaScript developer you probably heard about smoosh-gate. Some TC39 people (who are responsible for designing the ECMAScript standard that defines the langauge behaviour of JavaScript) had the idea to rename flatten to smoosh and flatMap to smooshMap. The rational behind this being some websites who use MooTools would break if they don't. These methods are a proposal right now and not part of the standard.

Anyway, I don't know much about MooTools or standards, but I wanted to explain what these functions acutally do.

Why

Most of the time, when programming JavaScript, you are probably messing around with your most favorite functors, arrays and promises. Sometimes they are nested, but you don't care about this. You need an array of numbers and not an array of arrays of numbers or you need a JSON result from your server and not a promise of a promise of JSON result.

What

Promises already come with a then method, that flattens out nested promises.

// loadDataA returns a promise
const dataAPromise = loadDataA();

// dataAPromise resolves to a result with an id that is used to load the next data
// loadDataB returns a promise too
const dataBPromise = dataAPromise.then(result => loadDataB(result.id))

// dataBPromise resolves to the resulting data
// and not the the promise returned from the callback above.
// It's flattened out right away so you only care about the result
const upperCasePromise = dataBPromise.then(result => result.someText.toUpperCase())

// upperCasePromise resolves to the upper case text
// returned by the previous callback.
upperCasePromise.then(upperCaseText => console.log(upperCaseText));
Enter fullscreen mode Exit fullscreen mode

So there isn't much to do here. Some promise libraries like Bluebird come with seperate map and flatMap methods, but mostly you will use then and don't care too much about flattening here.

The solution for this problem in arrays was to add a flatten and flatMap method to arrays. The flatten method replaces every nested array in the array with the content of that nested element, it also removes empty elements.

This function could be written manually with the help of reduce.

const flatten = a => a.reduce(
  (newArray, element) =>
    element instanceof Array
      ? [...newArray, ...element]
      : element !== undefined? [...newArray, element] : newArray,
  []
);

const a = [1, [2, 3, 4], , 5];
flatten(a); // -> [1, 2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

We reduce a to a newArray by adding every element to it, if this array is an istanceof Array we add every element of that element to the newArray. (The ...-operator will create a new array for either case instead adding to the existing array, but I think you get the point).

The imperative version could look like that:

function flatten(a) {
  let b = [];
  for (let element of a) {
    if (element instanceof Array) {
      for (let subElement of element) {
        b.push(subElement);
      }
    } else if (element !== undefined) {
      b.push(element);
    }
  }
  return b;
}

const a = [1, [2, 3, 4], , 5];
flatten(a); // -> [1, 2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

The flatMap version of this is simply calling flatten on a new array that was emitted by a map.

const flatMap = (f, a) => flatten(a.map(f));

const a = [1,0,7,-3];
flatMap(x => x != 0? 1/x : undefined, a);
// -> [1, 0.14285714285714285, -0.3333333333333333]

const c = [1,2,5];
flatMap(x => ''.padEnd(x, ".").split(""), c);
// -> [".", ".", ".", ".", ".", ".", ".", "."]
Enter fullscreen mode Exit fullscreen mode

The real implementations will probably work like methods and not functions:

// Instead of 
flatten(a.map(x => [1,x]));

// it would be
a.map(x => [1,x]).flatten();

// instead of
flatMap(x => [1,x], a);

// it would be
a.flatMap(x => [1,x]);
Enter fullscreen mode Exit fullscreen mode

Conclusion

Flatten is a rather important action performed many times in every program, so it would be nice if JavaScript came with a built-in version, independent of its final name, lol.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player