Unpacking JavaScript 3: Async Code - Method Chaining
Tags: javascript, webdev, tutorial, beginners
Published: 2022-09-05 13:04:43

This article will not introduce Async code yet, but sequential programming, which is actually a good segue to promises and async code.

for us a sequential program is as easy as it sounds, a program with components that execute in sequence based on a previous component in the sequence(chain)

e.g String operations in JS 

```js


"Hello World".split("").reverse().join("")

  // split reverse and join will execute in sequence based on the
  // previous component's(object) result
```

This sequence or chain formed by these functions is formally known as method chaining.

## Method Chaining(MC)

a simple, even not complete explanation of MC to build from would be: passing down an object from method to method in a chain

let's think about objects a bit

### Dot operations and Objects

Dot Op examples

```js

.forEach()
.toString()
.call()
.bind()


```
A dot operation accesses a property of an object.

 ```js
 
const simpleObject = {
  name: "sk"

}



console.log(simpleObject.name)  // sk  - produce by a simple dot op 
 
```

Dot op's assumption in JS is fairly simple: Dot op assumes whatever is being operated on is an object(whether during runtime or declaration), the right side of the dot assumes the left is an object

```js
let str = new String("hello")

let arr = new Array()


 
console.log(typeof str)  // Object 

console.log(typeof arr)  // Object

str.split()
arr.forEach()

// fun fact most primitives in JS are turned to objects during
// runtime, hence it's possible to dot operate on a primitive 
// e.g string  "Hello world".split() 

```


 what's the point of all this?

```js
 yAxisG
 
 .append("text")

 .attr('class', 'axis-label')

 .attr('y', -80)

 .attr('x', -innerHeight / 2)

 .attr('transform', `rotate(-90)`)

 .attr('fill', 'black')

 .attr('text-anchor', 'middle')

 .text(YaxisLabel)



```
what you looking at is a snippet of D3, a JS visualization library, chaining multiple dot operations, we said the right side of dot ops assume the left is an object.

let's look at append from D3


```js
append("text").attr("class", "axis-label")

// attr assumes append is an object, not only an object, but one 
// that has a property attr, which is a function

// this is what attr assumes 

const append = {
    attr: function(arg1, arg2){
	
	    // do some attr stuff
	}

}

append('text').attr()

// however if you observe carefully append is not an object, 
// but a function("text") taking a text arg ,
// so how is this possible, simple 
// append returns an object with the method attr 
// and that is what method chaining is: passing down an object //from method to method in the chain
// will make sense as we implement it


```

append returns an object with the attr method, attr returns an object with the attr and text method and so on,
but we do not have to define the shape of the passed objects by "hand", we have OOP for that, we know that the `this` keyword refers to the context around it, if called inside an object `this` refers to that object, we can achieve method chaining by having a bunch of methods in an object, each function after doing it's job, returns `this`, which refers to the current object

```js
const chainable = {

	 one : function() {

	 console.log("one")

	 return this;    // this === chainable object

	 }, 
	 

	 two: function () {

	 console.log("two")

	 return this



	 },

	 three: function() {

	 console.log("three")

	   return this;

	 }

  
  
  

}


  

chainable.one()

.one()

.one()

.two()

.three()

.one()

// you can create a huge sequence as you can see above, each 
//method will return chainable
// to take it a step further you can even encode state in chainable and have it updated as you go along
// it's very easy

```

each method in chainable returns well: the chainable object, each dot operation in the chain expects the previous one to return an object, which defines the accessed property for example 

```js
chainable 
.one()  // expects chainable to have method one 
.two() // expects one() to have method two(), which does not but returns an object that does

// and so on


```

you can achieve this with classes also.

```js

class Axis{


	append(text){
        // do something with text 
		console.log(text)
		return this; // current instance object 
       

	}
	
	attr(key, property){
	  // do something 
	  console.log(key, property)
	  
	  return this 
	
	}
	
	text(text){
	 // do something 
	 console.log(text)
	 
	 return this 
	
	}


}


const yAxis = new Axis()

yAxis
.append("hello world")
.attr("zIndex", 1)
.attr("backgroundColor", "black")
.text("hello again")
.text("good bye")
.attr("display", "flex")





```


With that we achieve sequential programming, doing an operation based on the previous one, this is a good Segue to promises, as this is what promises are (kind of), methods that return objects called promises, these objects define then, catch and finally methods(sound familiar?)

next we will introduce promises