0

I want to loop through a list of existing classes and call their methods. The simplified version looks like this:

class Animal { 
  speak() {
    return this;
  }
}
const classNameStr = 'Animal';

eval(`${classNameStr}.prototype.speak()`);

But eval() is obviously bad practice. Is there an alternative?

  • 2
    eval is a bad idea and not sure how calling the protoype method is going to work. Don't you want to loop over an instance of Animal? – epascarello Jul 16 '19 at 15:39
  • 4
    @epascarello that's exactly what he said in the question. – MauriceNino Jul 16 '19 at 15:39
  • 1
    Without knowing any more about the larger codebase, this seems like a design flaw. If you really need this functionality, you should consider re-factoring a bit to not require the use of `eval` (or any equivalent) at all. – esqew Jul 16 '19 at 15:41
  • https://stackoverflow.com/questions/1664282/javascript-refer-to-a-variable-using-a-string-containing-its-name – epascarello Jul 16 '19 at 15:41
  • Use an object to store references to your class instances – charlietfl Jul 16 '19 at 15:42
  • Creating an instance of `Animal()` will give you an object that you can reference in many ways. Probably an array of these objects would suit your requirements, but without more information it's difficult to do anything more than guess. – Reinstate Monica Cellio Jul 16 '19 at 15:42
  • `window['Animal'].prototype...` – dandavis Jul 16 '19 at 15:45

2 Answers2

0

You could implement a factory pattern https://medium.com/front-end-weekly/understand-the-factory-design-pattern-in-plain-javascript-20b348c832bd

Will
  • 205
  • 1
  • 8
0

You don't need eval, you need objects.

"use strict";

const animalClasses = {
  Animal: class { 
    speak() {
      return this;
    }
  },
  Wolf: class extends Animal {
    speak() {
      console.log("Wooooooooo");
      return super.speak();
    }
  }
};

function speakAnimal(classNameStr) {
  animalClasses[classNameStr].prototype.speak();
}

However calling methods via the prototype like that is error prone and flat out weird.

We can and should revise it to

function speakAnimal(classNameStr) {
  const animal = new animalClasses[classNameStr];
  animal.speak();
}

More generally, one would write something like

"use strict";

const createAnimal = (function() {
  const animalClasses = {
    Animal: class { 
      speak() {
        return this;
      }
    },
    Wolf: class extends Animal {
      speak() {
        console.log("Wooooooooo");
        return super.speak();
      }
    }
  };

  return function (animalName) {
    return new animalClasses[animalName];
  }
}());

And then consume it like this

const name = "Wolf"

const animal = createAnimal(name);
animal.speak();
Aluan Haddad
  • 29,886
  • 8
  • 72
  • 84