1

I'm trying to understand how chaining functions work in JavaScript. I have two examples:

First

    class Arithmetic {
      constructor() {
        this.value = 0;
      }
      add(value) {
        this.value = this.value + value;
        return this;
      }
     subtract(value) {
     this.value = this.value - value;
     return this;
     }
   }

You can do chain the methods by instantiating let a = new arithmetic(); and a.add(3).subtract(4);

Second

var zappo = function(selector) {
  var el;

  var obj = {
    getEl(selector) {
    return document.querySelector(selector);
    },
    addClass(className){
    el.classList.add(className);
    return this;
    }
  }

  el = getEl(selector);
  return obj;
}

I can chain these methods by zappo(#main).addClass("green").addClass("red");

My question is why is the first constructor function able to chain functions without having the methods within an object whereas the second function requires all the methods to be within an object?

Kevvv
  • 3,655
  • 10
  • 44
  • 90
  • 2
    You're able to chain because the methods are returning a reference to itself `return this;`, the hidden question Classes vs Objects can be answered here: https://stackoverflow.com/questions/17525450/object-vs-class-vs-function#17525749 – Pedro Costa Feb 27 '19 at 17:28
  • In your second example, `getEl` should not be a method of the object at all – Bergi Feb 27 '19 at 18:18

2 Answers2

6

My question is why is the first constructor function able to chain functions without having the methods within an object...

They methods are in the object, because the object inherits from its prototype, and the methods are defined on the prototype.

Do methods have to be within an object to be chained together?

By definition, methods are only accessible on objects (or JavaScript's primitives that effectively but not literally get promoted to objects), because otherwise we call them functions, not methods.

Method chaining isn't anything special. All you're doing when you do x.a().b() is calling a on x and then calling b on whatever it is a returns. In your class example, each method does return this so each returns the object it was called on. But you can just as easily use x.a().b() when a returns an object that isn't x. It's actually very common. Example:

document.querySelector("div").addEventListener(/*...*/);

querySelector doesn't return document, it returns the element that was found. The above assumes an element will be found and returned (rather than querySelector returning null) and calls addEventListener on that element.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • What would be an example of method chaining from a non-constructor where the methods are not in an object? – Kevvv Feb 27 '19 at 18:20
  • 1
    @Kevvv - The methods are in an object regardless. I think I may have misread your title. I read it as "the *same* object" but what you wrote was "*an* object." I've updated the answer slightly to fix that. – T.J. Crowder Feb 27 '19 at 18:23
1

It doesn't require it:

 class zappo {
  constructor(selector) {
    this.el = document.querySelector(selector);
  }

  addClass(className){
   this.el.classList.add(className);
   return this;
 }
}
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151