Search code examples
javascriptnode.jsprototypechaining

Defining which method can be chained


I created a class that supports chaining by making use of return this;, and now I need to make the current method tell what methods can be chained. Example:

class MyClass {
  constructor(path) {
    this.path = path;
  }

  method1() {
    // some code here...
    // i must make something here to only allow channing if it's method
    // blabliblu
    return this;
  }

  blabliblu() {
    // some code here...
    // same thing here, if the channing is with the method ar_2, it's ok.
    return this;
  }

  ar_2() {
    // And so on...
    return this;
  }
}

So, i can do: method1().blabliblu(), but i can't do method1().ar_2(). Is there lib to help me achieve this?


Solution

  • What you have asked for is not possible in Javascript. When you do:

    return this;
    

    in your methods, you are returning the same object. Any public method can be called on the object that is returned and there is no way to specify that because the object was returned from a method it should somehow not allow some methods to be called.

    So, using the code in your example where you return this in .method1(), there's no difference between this:

    obj.method1();
    obj.ar_2();
    

    and this:

    obj.method1().ar_2();
    

    That's because the chained version is essentially this internal to the JS interpreter:

    let temp = obj.method1();
    temp.ar_2();
    

    So, if temp is the same as obj which it is when you return this from method1(), then obj.method1().ar_2(); is just the same as obj.method1(); obj.ar_2(); (with a little less typing). Thus, you can't prevent the calling of .ar_2().

    Both just call .method1() and then .ar_2() on the same object. So you can't prevent one scheme, but allow the other. ar_2 is either a public method or it isn't. You can't have it callable in one place and not callable in another on the same object.


    Now, you could make obj.method1() return a different object. If you did that, then that different object could have different methods on it and could be an object that does not have a .ar_2() method.

    When you chain array methods like this:

    let result = [1,2,3].map(...).filter(...);
    

    Each step in that chain is returning a different object (they are not doing a return this, but are creating a new object and returning it. In this specific Array example, these are returning different objects, but of the same type, but you could return different objects of different types. For example:

    let result = ["a","b","c"].join("").toUpperCase();
    

    Here, .join() is an Array method, but returns a string object which you can then only call string methods on. So, you could do something like that where you return a different type of object.