rockchalkwushock
rockchalkwushock

Reputation: 1273

Daisy chaining methods in JavaScript

This came to may mind over the weekend and I was curious to know exactly what is happening when one chains methods together like the below code:

const posts = [{}, {}, {}, ...]

posts
  .filter(({ node }) => node.fields.slug !== '/about/')
  .reverse()
  .slice(0, 5)

Each of the Array.prototype methods returns an array after transforming the data in some fashion. filter & slice are both returning copies of the original array with the prescribed transformation present. What I am curious to know is if JavaScript is performing some internal piping like I would see in elixir. Each method requires an array to work, but not necessarily as an argument, I think.

I don't believe the above is similar to. I know that the first arg must be whatever is returned from the prior operation for the pipe operator to work in elixir:

posts
  |> filter(({ node }) => node.fields.slug !== '/about/')
  |> reverse()
  |> slice(0,5)

Wasn't sure where to look to better understand this so if you can point me in the right direction I'll go read up on it. I was just curious to know, thanks so much for the information.

Upvotes: 3

Views: 1640

Answers (1)

DJDaveMark
DJDaveMark

Reputation: 2855

It's nothing more complicated than returning either this or some other new object. A simple example would be:

function Num(val) { // Num contructor
    this.val = val;
};

Num.prototype.increment = function () {
    this.val++;
    return this;
}

Num.prototype.decrement = function () {
    this.val--;
    return this;
}

Num.prototype.getVal = function(){
    return this.val;
}

var num = new Num(0);
num.increment().increment().decrement().increment();
console.log(num.getVal()); // 2

The non-chaining way would be:

var num = new Num(0);
num.increment();
num.increment();
num.decrement();
num.increment();
console.log(num.getVal()); // 2

A good reason to use chaining is when the method returns a new immutable object (e.g. string) but you don't care about the intermediary objects, you just want the final result:

var username = " Dave"; // user input with leading whitespace
var lowercase = username.trim().toLowerCase(); // "dave"

Not using chaining in this case wouldn't produce the desired result (no whitespace):

var username = " Dave"; // user input with leading whitespace
username.trim();
var lowercase = username.toLowerCase(); // " dave"

You could still avoid chaining though if you reassigned the return value:

var username = " Dave"; // user input with leading whitespace
var lowercase = username.trim();
lowercase = lowercase.toLowerCase(); // "dave"

And just for completeness, if you wanted to make the above Num example immutable:

Num.prototype.increment = function () {
    return new Num(this.val + 1);
}

Upvotes: 3

Related Questions