34

I have a simple class with a single method exec(arg1,..,argn) and I want to have a number of alias methods which call exec with predefined argument values (e.g. exec_sync = exec.bind(this, true)).

The following does the trick:

class Executor {
  constructor() {
    this.exec_sync = this.exec.bind(this, true);
  }

  exec(sync, cmd, args/* ... */) {
    // impl
  }
}

But I don't know if this is a good idea or if this is idiomatic to ES6.

UDATE:

In a real-life example I have two nested loops with respectively 3 and 4 loops, which are used to dynamically add a total number of 12 alias methods to the class. It would be a cumbersome task to explicitly define the alias methods when you actually can take advantage of JS being a prototype-based programming language.

UPDATE 2 - EXAMPLE:

Suppose we have have a simple HTTP client with a method request(method, body) and we want to provide alias methods for GET, PUT, etc. It would look something like the following:

class HTTP {
  constructor() {
    ['GET', 'PUT', 'POST', 'DEL'].forEach((method) => {
      this[method] = this.request.bind(this, method);
    }, this);
  }

  request(method, body) {
    // execute the HTTP request
  }
}
Yan Foto
  • 10,850
  • 6
  • 57
  • 88
  • Why not create multiple functions explicitly? `exec_sync(...args) { return this.exec(true, ...args); }` – zerkms Sep 10 '15 at 08:32
  • @zerkms I think that would be more clear what the class does. I was just interested about the possibility of doing something like that. – Yan Foto Sep 10 '15 at 08:34
  • ES6 classes are just syntactic sugar. Nothing changed in terms of adding properties to an object at runtime. – Felix Kling Sep 10 '15 at 15:50

3 Answers3

48

Your solution is fine, though it'll be better to create all those methods once on a prototype level:

['GET', 'PUT', 'POST', 'DEL'].forEach((method) => {
  Executor.prototype[method] = function (body) {
    return this.request(method, body)
  }
})

prototype approach is slightly faster, because this code is executed only once, while constructor code is executed every time new instance is created.

Another advantage of prototype over constructor is that its compatible with classes inheritance. So, if you'll extend your class later nothing will break even if you'll redefine any of those methods.

By the way, you can use require('http').METHODS or methods package instead of hard-coded array of HTTP verbs here.

Leonid Beschastny
  • 50,364
  • 10
  • 118
  • 122
  • 1
    Thanks. the http stuff should have been an example, I don't use it in my code :) – Yan Foto Sep 10 '15 at 09:51
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/89272/discussion-between-yan-foto-and-leonid-beschastny). – Yan Foto Sep 10 '15 at 11:31
4

I like @leonid's answer, but is there a way to allow mangling when you using dynamic computed property names.

['VERYBIGNAME', 'VERYBIGNAME2', 'VERYBIGNAME3'].forEach((method) => {
   Executor.prototype[method] = function (body) {
     return this.request(method, body)
   }
})

in your minified and mangled javascript these VERYBIGNAME strings will exist.

so if I am able to get references to these VERYBIGNAME functions can I use something like

const references = { VERYBIGNAME1, VERYBIGNAME2, VERYBIGNAME3 };

Object.assign(Executor.prototype, { ...references });
BoltCoder
  • 194
  • 5
1

I don't know about this being idiomatic (since it's more about design, rather than programming language itself), but I personally think creating explicit functions would be better:

exec_sync(...args) {
    return this.exec(true, ...args); 
}
zerkms
  • 249,484
  • 69
  • 436
  • 539
  • 1
    In a real-life example I have 2 nested loops that respectively have 3 and 4 items used to dynamically add a total of 12 items to the class. it would be a little cumbersome to add everything manually. – Yan Foto Sep 10 '15 at 09:11
  • @YanFoto I would think about moving it to a separate class actually then. – zerkms Sep 10 '15 at 09:14
  • Those methods actually and semantically belong to the class. If I move them to a separate class, I would still need to define them explicitly. or am I missing something here? – Yan Foto Sep 10 '15 at 09:17
  • @YanFoto those are just helpers-wrappers. But again, it's a matter of taste or preferences in design. There is no single *objective* answer for that. – zerkms Sep 10 '15 at 09:18
  • I appreciate your help. I provided an example to clarify the situation in some extent. I want to avoid the next developer considering my code as *ugly* :D – Yan Foto Sep 10 '15 at 09:25
  • @YanFoto every code is ugly unless it's written by yourself ;-D – zerkms Sep 10 '15 at 09:28
  • this is inefficient, defeats the purpose, but would work – Alexander Mills Oct 09 '17 at 06:39
  • @AlexanderMills inefficient compared to *what*? – zerkms Oct 09 '17 at 06:42
  • ok it's simple, you have defined this.exec as a top level function, which means it's called every time a new object is created by the constructor, if you use the prototype function with having to define exec in the constructor, it would be better. But it appears that ES6 makes it difficult to have "dynamic" prototypes. – Alexander Mills Oct 09 '17 at 06:47
  • @AlexanderMills "you have defined this.exec as a top level function" --- I have not. It's a class method. "which means it's called every time a new object is created by the constructor" --- it won't, it's a class method, so it will be created on a prototype. – zerkms Oct 09 '17 at 06:47