1

I have several different classes with the same duplicate code. Aside from the different identity of each's this, these duplicate code are all ostensibly identical.

Here's a simplified example:

class classA {
  ...

  doSomething() {
    if (!this.id || !this.data || !this.isAllowed()) {
      return null;
    }
    return someImportedFunc(this.data, this.metadata, this.doSomethingElse());
  }
}

class classB {
  ...

  doSomething() {
    if (!this.id || !this.data || !this.isAllowed()) {
      return null;
    }
    return someImportedFunc(this.data, this.metadata, this.doSomethingElse());
  }
}

// Many other classes like this

I've thought of moving the doSomething method to another class, then importing it in all these classes. But that would result in a very messy method that takes many, many arguments to account for all the different this's. It'd look like:

class exportedClass {
  function doSomething(id, data, metadata, isAllowed, doSomethingElse) {
    if (!id || !data || !isAllowed()) {
      return null;
    }
    return someImportedFunc(data, metadata, doSomethingElse());
  }
}

class classA {
  ...

  methodThatUsesDoSomething() {
    const result = exportedClass.doSomething(
        this.id, this.data, this.metadata, this.isAllowed, this.doSomethingElse);
    ...
  }
}

Except with like 15 args instead of 5 since this is a simplified example.

How can I avoid duplicate code in this kind of situation?

user3932000
  • 671
  • 8
  • 24
  • Are you open to use inheritance in this case ? – Nalin Ranjan May 14 '22 at 05:42
  • *I have several different classes with the same duplicate code.* Why? – connexo May 14 '22 at 05:48
  • Indeed another way would be to abstract the required properties into an interface and then pass that interface to `doSomething` method... given all these classes do realize that interface as well, which should help passing `this` alone as the sole argument. – Nalin Ranjan May 14 '22 at 05:49
  • @NalinRanjan I'd prefer a non-inheritance solution to avoid a lot of refactoring. But I am open to using inheritance. – user3932000 May 14 '22 at 05:50
  • @connexo I have many different related classes extending the same superclass. These classes must all support the same functionality (but tailored to its own use case). – user3932000 May 14 '22 at 05:53
  • 1
    How is their code then *same duplicate code*? Why is this same duplicate code not part of the super class? – connexo May 14 '22 at 05:56
  • @connexo The superclass is owned by a different team and is used across many teams in the company. I cannot make any changes to it. – user3932000 May 14 '22 at 05:59
  • Does this answer your question? [How to add mixins to ES6 javascript classes?](//stackoverflow.com/q/42247434/90527), "[ES6 Class Multiple inheritance](//stackoverflow.com/q/29879267/90527)". See also the many other questions on this site about implementing multiple inheritance and mixins in JS. – outis May 14 '22 at 06:48
  • Why would you need to pass any of the properties on `this`, or even `this` itself as arguments? They're already accessible via `this`. What's your understanding of objects and object fields? – outis May 14 '22 at 06:51
  • @outis I cannot use an outside mixin, unless JS somehow supports dynamically determining context in a mixin function referencing `this`. (Since the mixin would need to make use of properties of the object getting extended.) – user3932000 May 14 '22 at 07:15
  • @outis I don't quite follow your follow-up question. These are instantiations of separate classes, each with its own `this`. My initial idea (with the many params) is an exported function that lives outside both `classA` and `classB`. Perhaps this was unclear, so I've edited the question. – user3932000 May 14 '22 at 07:16
  • @user3932000: In a method, `this` is bound to whichever object its called on, and is independent of the method. It's only bound to a specific object if [`bind()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) is used. That is why & how mixins work, by the way. – outis May 14 '22 at 07:27
  • … If you add function to an object as a property & then call it, or use [`apply`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) or [`call`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call), the value of `this` within the function is bound to the appropriate object. Why do you think you need to pass an object's properties to a method? Hence my questions about your understanding of objects. This post doesn't jibe with JS's object model. – outis May 14 '22 at 07:28

1 Answers1

1

Assuming you want a non-inheritance solution, my suggestion would be to pass "this" as an argument, as prototypes can be manipulated as parameters. That would allow you to keep the parameters at a minimum while not losing data.

Pew
  • 64
  • 8