Keep Your Methods Chained 🔗🔗🔗
Tags: javascript, webdev
Published: 2021-03-24 16:57:47

Chaining methods is something that you have likely done at some point and you may not have even realized it. If you haven't then you will definitely have seen it in other people's code. This is what it looks like when you chain methods.

```js
let names = ['Tony', 'Adesh', 'Robert', 'Su Cheng'];
//want to run both filter and map on this array.
names = names.filter(someFunc).map(otherFunc);
```

We will look at an expanded version of this and explain all the details below.

## What is Chaining

The process of programming is simply sequential problem solving. We break a problem down into small logical steps and decide the best order to execute those steps.

By chaining our methods we can leverage best practices like `pure functions`. We can create our small logical steps with pure functions.

> A `pure function` is one that will always provide the same output for the same input and it can't have any side effects - like changing the value of something outside the function that had nothing to do with the input or output values.

This article has a logical sequence to it. It is divided into sections. The sections are split into paragraphs. The paragraphs are split into sentences. The sentences are split into individual words. The sequence of each of those steps matters. Change the steps at any level and the tutorial fails. Just like your program.

Chaining your methods is a way that you can hard code, in a very readable way, the steps that you are taking.

```js
let result = myobject.stepOne().stepTwo().stepThree();
```

## How Does Chaining Work

The ability to chain them does have some restrictions. The result of the first step must be an Object or datatype that is capable of initiating the next step.

JavaScript will automatically read and execute these steps from left to right. 

When it completes the final step then the result will be returned and assigned to the waiting variable on the left side of the `=`, if there is one.

As long as you are returning a valid object type for the next method, then you can keep chaining.

Here is a simple example with a couple of built-in methods - `Number.prototype.toFixed()`, and `Number.parseFloat()`.

```js
let pie = '3.1415 is the approximate value of PI';
let num = parseFloat(pie).toFixed(2); 
```

The value of num will be "3.14". The global method `parseFloat` accepts a string and extracts the left-most digits, decimal is permitted. It will return a `Number`.

The `toFixed` method can be run on a `Number`. It will use its argument and convert the `Number` to the `String` equivalent of the `Number` with the correct number of decimal places. 

The longer way to write this would have been to add the first method on its own line and create another variable to hold the value of the middle step.

```js
let pie = '3.1415 is the approximate value of PI';
let middle = parseFloat(pie);
let num = middle.toFixed(2); 
// the value of num will be "3.14"
```

Chaining our methods saves that middle step. No creation of an extra variable. No extra line of code. We can just read the steps on a single line. 💯

## Can I Chain my own Methods

If you are building your own `Object`(s) then you can also chain your own object methods, as long as you follow the same rule - return the correct datatype to be used in the next method.

Here is an example with a Person 🧔 object. (The object could be built with the `class` syntax too).

```js
const Person = function(_name){
  this.name = _name;
}
Person.prototype.speak = function(_phrase){
  console.log(`${this.name} says, "${_phrase}"`);
}
Person.prototype.drink = function(_beverage){
  console.log(`${this.name} is enjoying a ${_beverage}`);
}
```

With our `Person` object we can now instantiate a person and call the methods.

```js
let rashad = new Person('Rashad');
rashad.speak('Do your homework');
rashad.drink('coffee');
```

Everything works just fine. But we can't chain `speak` or `drink`. Both functions return the default `undefined`.

However, if we add a return statement and return our `Person` object that we instantiated...

```js
Person.prototype.speak = function(_phrase){
  console.log(`${this.name} says, "${_phrase}"`);
  return this;
}
Person.prototype.drink = function(_beverage){
  console.log(`${this.name} is enjoying a ${_beverage}`);
  return this;
}
```

> We don't want to add a `return` to the constructor function because it has to return the newly created instance.

**NOW** we can chain our methods and it **WILL** work 🙌.

```js
let vladimir = new Person('Vladimir');
vladimir.speak('I am thirsty').drink('beer');
```

And just like that, you're almost ready to flex 💪.

## Add Some Functions to the Mix

We have a couple simple methods on our `Person` 🧔 object, but we are still using really simple code.

What if our methods internally called on other functions? What if they accepted other functions as a supplied argument? How do we keep chaining and keep our methods pure? 

Let's add an `eat` method to our `Person` object. We *could* just pass a String to the method with the name of the food. However, passing in a function that will choose a food item for us from some other source is a more practical and realistic way to do this.

...or why not both?

![Why not both?](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m3e8bqxz2k7e82cuc0po.gif)

First, we add the new `eat` method to our `Person` 🧔 object.

```js
Person.prototype.eat = function(source){
  let food = '';
  switch(typeof source){
    case 'string':
      food = source;
      break;
    case 'function':
      food = source();
      break;
  }
  console.log(`${this.name} is eating ${food}`);
  return this;
}
```

Now our method can accept either a `Function` to call to get the food OR a `String` with the name of the food.

It can also be chained because it returns some `Object` that has other methods which could be called.

Here is an example of a food function that could be used.

```js
const food = function(){
  let types = ['a slice of pizza', 'two tacos', 'some sushi', 'a burrito'];
  return types[Math.floor(Math.random() * types.length)];
}
```

And now our new method as part of our chained method code.

```js
let sarah = new Person('Sarah');
sarah.speak('Hello').drink('tea').eat(food).speak('That was great!');
```

We run this code and we get something like this:

```
Sarah says, Hello
Sarah is enjoying a tea
Sarah is eating two tacos
Sarah says, That was great!
```

Start flexing 💪!

## Common Array Method examples

Let's move back to that original example with the Array methods - `filter` and `map`.

```js
let names = ['Tony', 'Adesh', 'Robert', 'Su Cheng'];
names = names.filter(someFunc).map(otherFunc);
```

The `Array.prototype.filter` method will take a function as its parameter and run that function once on each item in the array. The `filter` method's function must return `true` or `false` for each item. `true` means keep the item. `false` means dispose of the item. After calling the function once per item, the `filter` method will return a new Array built based on those `true` and `false` responses from the function calls.

This new `Array` will be used to call the `map` method.

The `Array.prototype.map` method will take a function as its parameter and run that function once on each item in the array. The `map` method's function can return anything it wants. The `map` method builds a new `Array` containing all those returned values. The new `Array` will always have the same number of items as the `Array` that called the `map` method.

The new `Array` returned from the `map` method, since there is nothing chained onto it, will be assigned to the variable `names`.

Now you know how to chain your methods and why you want to. 

Good for you! 🏆🥇💯🙌

If you want to learn more about Arrays, Functions, Javascript or practically any web development topic: please check out my [YouTube channel](https://www.youtube.com/c/SteveGriffith-Prof3ssorSt3v3/videos) for hundreds of video tutorials.