⛓ JavaScript Method Chaining
Method chaining is a common pattern in the JavaScript world, which you may have seen before if you’ve ever used jQuery or Moment.js.
// Chaining in jQuery $('#example').height(100).fadeIn(200); // Chaining in Moment.js moment().startOf('day').fromNow();
This tutorial will provide a brief explanation of what method chaining is, provide a few more real-world examples, and teach you how to implement it yourself! 🚀
What is Method Chaining?
Method chaining is a technique to simplify code in scenarios that involve performing multiple operations on the same object. Here are a few examples demonstrated using jQuery.
/** Example WITHOUT method chaining */ let $div = $('#my-div'); $div.css('background', 'blue'); $div.height(100); $div.fadeIn(200);
/** Example WITH method chaining */ $('#my-div') .css('background', 'blue') .height(100) .fadeIn(200);
As you can see, using method chaining can tidy up code quite a bit for performing a large number of operations in a row. But how does it work, exactly?
Understanding Method Chaining
To demonstrate the concept, we’ll use a contrived example—a Kitten
class—with a few methods to call. Let’s create a Kitten
class:
class Kitten { constructor() { this.name = 'Garfield'; this.color = 'brown'; this.gender = 'male'; } setName(name) { this.name = name; } setColor(color) { this.color = color; } setGeneder(gender) { this.gender = gender; } save() { console.log( 'saving ' + this.name + ', the ' + this.color + ' ' + this.gender + ' kitten...' ); // save to database here... } }
Now, let’s instantiate a kitten object from our class and call its methods.
let bob = new Kitten(); bob.setName('Bob'); bob.setColor('black'); bob.setGender('male'); bob.save(); // OUTPUT: // > saving Bob, the black male kitten...
Wouldn’t it be better if we could get rid of some of this repetition? Method chaining would be perfect for this. But, if we tried to chain our calls, it wouldn’t work; here’s why.
let bob = new Kitten(); bob.setName('Bob').setColor('black'); // ERROR: // > Uncaught TypeError: Cannot call method 'setColor' of undefined
To better understand why this doesn’t work, let’s rearrange the code slightly.
let bob = new Kitten(); let tmp = bob.setName('Bob'); tmp.setColor('black'); // ERROR: // > Uncaught TypeError: Cannot call method 'setColor' of undefined
This returns the same error. This is because the setName()
function doesn’t return a value, so tmp
is undefined
. Fortunately, this is an easy fix. To enable method chaining, we simply need to return the current Kitten
instance at the end of each method.
Implementing Method Chaining
Let’s rewrite the Kitten
class with the ability to chain methods.
class Kitten { constructor() { this.name = 'Garfield'; this.color = 'brown'; this.gender = 'male'; } setName(name) { this.name = name; return this; } setColor(color) { this.color = color; return this; } setGeneder(gender) { this.gender = gender; return this; } save() { console.log( 'saving ' + this.name + ', the ' + this.color + ' ' + this.gender + ' kitten...' ); // save to database here... return this; } }
Now, if we run the new code, the variable tmp
will reference the same object as the variable bob
, like so:
let bob = new Kitten(); let tmp = bob.setName('Bob'); tmp.setColor('black'); console.log(tmp === bob); // OUTPUT: // > true
Now we can remove the tmp
variable and chain our method calls directly. Here’s the final product:
/** Example WITHOUT method chaining */ let bob = new Kitten(); bob.setName('Bob'); bob.setColor('black'); bob.setGender('male'); bob.save(); // OUTPUT: // > saving Bob, the black male kitten...
/** Example WITH method chaining */ new Kitten() .setName('Bob') .setColor('black') .setGender('male') .save(); // OUTPUT: // > saving Bob, the black male kitten...
By using method chaining we can end up with much cleaner code that’s easier to understand.
Method chaining is an extremely useful technique to have in your programmer toolbox. And, even though we covered it in JavaScript today, implementation is extremely similar in any language.
I hope you learned something new and, if you have any questions or comments, feel free to reach me on Twitter @GregorySchier
Martin Mauchauffée and Manu Delgado Diaz pointed out that this is also known as the Fluent Interface pattern.
Юрий Тарабанько came up with a great way to automate the addition of return this;
. Check out his chainify()
function in this Fiddle
If you enjoyed this tutorial, please consider sponsoring my work on GitHub 🤗