0
  1. I have 2 Class defined somewhere else, all constructors need 3 parameters (a, b, c), but a, b(object), c(object) is in an Array

    var paramArr = [a, b, c];
    
  2. I would like to call these 2 Class via a parameter according to a dictionary object, like:

    var dict = {'a': 'A', 'b': 'B'};
    

    then,

    callClass(x){
      var className = dict[x];//string
      new className();
    }
    
  3. So, first I tried to do is something like eval so that I could call the Class with it string name.

    callClass(x){
      var className = dict[x];//string
      var classFn = new Function(this, 'new ' + className + '()');
      classFn();
    }
    
  4. still works fine. at last I should add the args by Fn.prototype.apply(), then I had to say all messed up:

    callClass(x){
      var className = dict[x];//string
      paramArr.unshift(null);
      var functionBodyStr = 'return new (Function.prototype.bind.apply(' + className + ', '+ paramArr +'))';
      var classFn = new Function(this, functionBodyStr);
      classFn();
    }
    

the classFn in the console will be:

    function(this){
      return new (Function.prototype.bind.apply(Classname, , a ,[object Object],[object Object]))
    }

it is something I expected but not all:

first, the 'null' value in the array is converted to disappeared, which leads to 'unexpected token ,'

second, all the other objects are converted to '[object Object]', which leads to 'unexpected identifier'

So, how could I apply a array param with null value? or this is a wrong way to do this?

GLPease
  • 545
  • 1
  • 8
  • 19
  • Please add the example of classes in your code that you are trying to invoke. If possible, create a working snippet using `<>`. – gurvinder372 Jan 10 '18 at 06:56
  • the classes are not decided yet, empty ones with constructors, just normal class like: , nothing fancy. – GLPease Jan 10 '18 at 07:18

1 Answers1

1

If I understand correct, you are trying to create object where class/constructor name is dynamically decided. For this, you can try using eval.

Using Eval

Idea

  • Create class/constructor name per your requirement.
  • Use eval to look for this function and get its scope.
  • If found, you can directly use new fn(...)
  • If not found, it will throw error so you will have to handle this case.

function MyClass1(a, b, c) {
  this.a = a;
  this.b = b;
  this.c = c
}

function MyClass2(a, b, c) {
  this.a = a;
  this.b = b;
  this.c = c
}

var classPrefix = 'MyClass';
var result = [];
for (var i = 0; i < 5; i++) {
  var functionName = classPrefix + (i % 3 + 1);
  var fn;
  try {
    fn = eval(functionName);
    result.push(new fn(i, i+1, i+2));
  } catch (ex) {
    console.log(functionName + ' was not found. Please check again.')
  }
}

result.forEach(function(obj) {
  console.log(obj.constructor.name, obj.a)
})

References:


Using HashMap

Idea of this approach is to have a list of possible classes with a map and use it to get reference dynamically. This is better/preferred than eval approach but it comes with an overhead of maintaining the map.

function MyClass1(a, b, c) {
  this.a = a;
  this.b = b;
  this.c = c
}

function MyClass2(a, b, c) {
  this.a = a;
  this.b = b;
  this.c = c
}

var functionMapper = {
  'MyClass1': MyClass1,
  'MyClass2': MyClass2,
}

var classPrefix = 'MyClass';
var result = [];
for (var i = 0; i < 5; i++) {
  var functionName = classPrefix + (i % 3 + 1);
  var fn = functionMapper[functionName];
  fn && result.push(new fn(i, i+1, i+2));
}

result.forEach(function(obj) {
  console.log(obj.constructor.name, obj.a)
})
Community
  • 1
  • 1
Rajesh
  • 24,354
  • 5
  • 48
  • 79
  • ya, your understanding is correct, that is exactly what I want to do. I use new Function(param, body) to avoid using eval :), and I don't see is how to apply the args in your snippet, that is the part I can not handle. :) can you add that part? – GLPease Jan 10 '18 at 07:22
  • @FadeocKhaos Updated my answer. As I have already specified, you will receive function reference in `fn`. So you can use it like a normal function. – Rajesh Jan 10 '18 at 07:26
  • @FadeocKhaos Please check the update. Added hashMap approach. – Rajesh Jan 10 '18 at 08:29
  • Thanks for your kind and detailed answer, I tried it, simple and works, though I am still worried a bit of using Eval, I ll head to your extra links to learn about it. About my question, I thought I lost null values when convert it to string, I asked this question by writting how I am thinking to avoid asking XY question, I eager for that answer too. Anyway I ll accept yours. Thanks. – GLPease Jan 10 '18 at 10:24