Chaining - Fluent Interfaces In JavaScript
Written by Ian Elliot   
Friday, 23 February 2018
Article Index
Chaining - Fluent Interfaces In JavaScript
Singleton Chaining
Initialization

Singleton Chaining

Before we get on to more complicated examples, let's examine another simple case - singleton chaining.

A singleton is a JavaScript object that isn't created by a constructor - it is an object literal.

In this case what we want to do is allow each function to be defined as a method of the same object - obj say. To allow chaining we have to arrange for each method to return an object that each subsequent function is defined on and in this case it is just obj. It really is this simple.

So let's define our object with three methods:

var obj = {
            function1: function () {
                alert("function1");
                return obj;
            },
            function2: function () {
                alert("function2");
                return obj;
            },
            function3: function () {
                alert("function3");
                return obj;
            }
        }

Notice that each function returns a reference to obj and this is what allows the next function call in the chain to work. With this definition you can write:

obj.function1().function2().function3();

and you will see the three alert boxes indicating that each function is called in turn.

Notice that this all depends on the variable obj not being reassigned between function calls. If you want to protect against this you need to create a private variable using closure that cannot be changed that the functions can return or you can use a const if you are using ES2015.

Instance Chaining

Singletons can be very useful, but often we want to be able to create as many instances of an object as desired and in this case we have to move on to look at instance chaining.

This is very similar to the singleton case, but now we have to create a constructor that will produce an instance of the object.

var objConstruct = function(){
            this.function1= function () {
                alert("function1");
                return this;
            };
            this.function2=function () {
                alert("function2");
                return this;
            };
            this.function3= function () {
                alert("function3");
                return this;
            }
        };

Notice that we have defined three methods for the object we are constructing, but also notice the use of "this" to reference the object being constructed.

What should each of the functions return to ensure that the next function can be called?

In this case each function has to return "this" because when the function is called "this" references the instance that the function is a method of.

Now we can write:

var obj = new objConstruct();
obj.function1().function2().function3();

and again we see the alert boxes announce that each function is called in turn.

If you can't see the difference between this and the singleton example, remember that we can now create as many instances of the object as we like. Also notice that because each function returns "this" as the object for the next function all of the function in the chain are called in the context of the same instance of the object.

Banner

Getting complicated

Once again this is all there is to chaining - just making sure you return the correct object for the next function to have the correct context.

If you want to be sophisticated then you don't always have to return the same object and, as already mentioned, this would be appropriate for a search method say that returned different types of object.

One problem with chained function calls is what do you do about the result of a function?

After all, you can't return it because to support chaining you have to return a suitable object.

The answer is that the object you return has to be both the context for the next function call and incorporate the result of the function.

That is, if you want to implement an API in a fluent style then you have to create an object which not only hosts the methods you want to chain but which stores what would have been the results of these operations as its internal state.

Let's take a look at some examples.

 

JavaScriptJems.SMALL



Last Updated ( Thursday, 13 June 2019 )