0

I have a namespace and class declared in the client. In fact, I have a whole bunch of classes declared in several namespaces. I just need to get an instance of one of them when I get a string from the server on page load that contains the "dotted" namespace.class names.

Currently I use eval to do that but this causes a memory leak, so I'm trying to find an alternative way of instantiating a declared object by knowing only its name. Things like var obj = "myNamespace.myObjectName"(); won't work, obviously.

If I have an object name as a string variable I can use the eval() function to create an instance of that object:

window["myNamespace"] = {};
myNamespace.myObjectName = function() { /* blah */ };

var name = "myNamespace.myObjectName";
var obj = eval("new "  + name + "()");

But for several reasons I don't want/cannot to use the eval. How can I create an object by its name without using the eval?

Alex
  • 566
  • 1
  • 6
  • 14
  • None of the answers in that question help in my situation. Please read the question carefully before marking it as a duplicate. – Alex May 11 '16 at 19:31
  • 1
    Are you saying you don't control the content of the `name` variable, so it must have the dot built in to the string? –  May 11 '16 at 19:36
  • I can't call "myNamespace.myObjectName"(); Please read the question. – Alex May 11 '16 at 19:36
  • 1
    The question is clear; the answer is that you have to traverse the object graph yourself with the "pieces" of the path to the function. – Pointy May 11 '16 at 19:38
  • The string comes from the server. I have that class declared in the client as myNamespace.myObjectName = function() { }; I just need to get its instance when I get its string name from the server: var instance = new ?? – Alex May 11 '16 at 19:38

1 Answers1

1

It sounds like you don't control the content of the name variable, so you're stuck with the . being part of the string.

Therefore, you can .split() the string into its name parts, and use .reduce() to traverse from the base object.

window["myNamespace"] = {};
myNamespace.myObjectName = function() {
  this.foo = "bar"
};

var name = "myNamespace.myObjectName";
var obj = newObjectFromStringPath(name);


document.querySelector("pre").textContent = JSON.stringify(obj, null, 4);


function newObjectFromStringPath(path, base) {
  return new (name.split(".").reduce(function(obj, name) {
    return obj != null ? obj[name] : null
  }, base || window))
}
<pre></pre>

The newObjectFromStringPath is coded to specifically target a function and call it as a constructor. You can easily make this work to fetch any value by simply removing the new in that function.