0

I have next class in many function in it :

class EventUtils {

    constructor(pid) {}
bindEvent1{}
bindEvent2()
...
}

I have to run those functions. Before ES5 I used something like this or this methods

However, after rewriting to ES6 classes those examples are not working any more. I had tried next code:

let eventUtils = new EventsUtils();

  Object.getOwnPropertyNames(eventUtils.__proto__).forEach((name) => {

     if (name.indexOf('bind') > -1) {                                        
        let fn = eventUtils[name];
        if (typeof fn === "function") fn.apply(null);
         }
   });

But in such way I the scope of this is not defined in applied function. What is the right way to do such coding?

AlexBerd
  • 1,368
  • 2
  • 18
  • 39
  • `the scope of this is not defined in applied function` it seems you are setting the `this` context to `null` in `fn.apply(null)` you should pass the context you wish to have instead of `null` – Nope Jul 28 '17 at 10:41
  • Just do `fn.call(eventUtils);` – Yury Tarabanko Jul 28 '17 at 10:41
  • @YuryTarabanko You war right it solved the problem. The question is: Is there are another solutions for such issue, more elegant and more es6 :) – AlexBerd Jul 28 '17 at 10:44
  • What is inside of these functions? – Jonas Wilms Jul 28 '17 at 10:51
  • Well, calling methods on a class via reflection produces Code that is hard to read and to maintain, therefore I would try to find another solution that uses explicit methodcalls. Especially if you are using a wildcard-thing like `name.indexOf('bind') > -1`, imagine what happens if someone adds another method to your class that does something else and should not be called by your loop. – treeno Jul 28 '17 at 10:53
  • I have more then 100 functions in this class and all of them starts with bind prefix. I can call all 100+ function one by one,but I think it would worst then simple foreach. I have to mention that this is not my code I only maintenance it :) – AlexBerd Jul 28 '17 at 10:55
  • 2
    Assuming that you have a good reason to use a reflective Approach, you could replace that by a simple Array that contains pointer to the functions that should be called. This way you don't need to Analyze the prototype and you don't Need to use a Wildcard-test on the function-names. The Code would be easier to read and you dont have the risk of calling unwanted functions – treeno Jul 28 '17 at 10:56
  • @treeno "by a simple Array that contains pointer to the functions that should be called." - Any example of such solution? – AlexBerd Jul 28 '17 at 10:58
  • 1
    something like `let binderList = [this.bindEvent1, this.bindEvent2, ...]` then you could do `binderList.forEach(binder => binder());` The disadvantage is that you have to list all functions in that Array... mmh maybe in that case you could also call them directly... – treeno Jul 28 '17 at 11:00

2 Answers2

2

Refering to proto is one of the worst thing you can do ( it will either not work or it 'll kill any optimizations) , maybe a simple for loop can help:

for(let key of Object.getOwnPropertyNames(Object.getPrototypeOf(eventUtils))){
 if(key.includes("Event") && typeof eventUtils[key] === "function"){
   eventUtils[key]();
 }
}

However, dynamic variable names are always a bad idea...

AlexBerd
  • 1,368
  • 2
  • 18
  • 39
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
2

Assuming all your function to be called were defined in prototype you could add custom bindAll method to prototype. And then simply call it on instance eventUtils.bindAll()

But the idea to have tens or even hundreds of function in prototype seems strange. You could better just use an array of functions to be called. So you could easily add, remove them, etc.

class EventUtils {
    constructor(pid) {
      this.pid = pid
    }
    
    bindEvent1() {
      console.log(`event 1 for ${this.pid}`)
    }

    bindEvent2() {
      console.log(`event 2 for ${this.pid}`)
    }
    
    bindEvent3() {
      console.log(`event 3 for ${this.pid}`)
    }
}

const addBindAll = ({prototype}) => {
 const fns = Reflect.ownKeys(prototype)
     .filter(key => key.startsWith('bind') && typeof prototype[key] === 'function' )
 
 Reflect.defineProperty(prototype, 'bindAll', {
  value: function() {
    fns.forEach(fn => this[fn]())
  },
  enumerable: false
 })
}

addBindAll(EventUtils)

let utils = new EventUtils(666)

utils.bindAll()
Yury Tarabanko
  • 44,270
  • 9
  • 84
  • 98