0

I have seen examples of how to do this that rely heavily on the browser environment but not examples that work in the native node.js environment.

I need to cast JSON objects to javascript classes of a type that does not yet exist but is given by an input string.

I found some nice code on stackoverflow to retype JSON to known class but I have not figured out how to do this when the class type is a string and the class does not exist.

In software terms I need to:

var className = 'Bar'; 
console.log(global[className]); // false - class Bar is not defined
var jsonIn = '{ "name": "Jason" }';
var retypedJson = retypeJSON(jsonIn, className);
console.log(retypedJson instanceof Bar)      // true

The code for recasting JSON. (Nice as it doesn't call eval or explicitly copy property names.)

// define a class
var Foo = function(name) {
  this.name = name;
}
// make a method
Foo.prototype.shout = function() {
  console.log("I am " + this.name);
}
// make a simple object from JSON:
var x = JSON.parse('{ "name": "Jason" }');
// force its class to be Foo
x.__proto__ = Foo.prototype;
// the method works
x.shout();
console.log(x instanceof Foo); // true

Thanks!

Community
  • 1
  • 1
Toaster
  • 1,911
  • 2
  • 23
  • 43
  • Do you know the object Bar? How do you create it? What if the input is none of the object you know? – DrakaSAN Sep 25 '14 at 08:44
  • @DrakaSAN Bar is a completely new class. The question is how to create it from a variable storing the string 'Bar'. – Toaster Sep 25 '14 at 08:54
  • 3
    javascript doesn't have classes. – webduvet Sep 25 '14 at 08:57
  • @Colin: How do you define which property have the object? In the string? What form? – DrakaSAN Sep 25 '14 at 08:58
  • @DrakaSAN The incoming JSON contains the necessary properties. – Toaster Sep 25 '14 at 09:11
  • So you just want to get the JSON, and copy field by field the JSON to a JavaScript object of type 'whateverisinthestring'? – DrakaSAN Sep 25 '14 at 09:12
  • @lombausch If it responds correctly to instanceof then it is a class. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof – Toaster Sep 25 '14 at 09:13
  • 1
    @Colin `instanceof` just checks if `Foo.prototype` is in object prototype chain – vkurchatkin Sep 25 '14 at 09:14
  • @vkurchatkin As I understand that would make the object an instance of a class of type Foo, in javascript. – Toaster Sep 25 '14 at 09:17
  • @Colin no, it doesn't, because javascript doesn't have classes – vkurchatkin Sep 25 '14 at 09:20
  • @vkurchatkin then what would you call it? I find numerous references that describe such constructs as classes in javascript eg. - http://www.phpied.com/3-ways-to-define-a-javascript-class/. – Toaster Sep 25 '14 at 09:23
  • @vkurchatkin I think the alternative term, 'named object', is a bit obtuse. – Toaster Sep 25 '14 at 09:30
  • If the JSON already have all the property, why do you need to translate it to a JS object? What do you try to achieve? You ll need a "class" (as you insist to name it) to know what to get from the JSON, or what property to add. – DrakaSAN Sep 25 '14 at 10:28
  • @DrakaSAN I would have said the same; however, I am using a third party application that requries named objects as input. I will likely pull the object name from the JSON. – Toaster Sep 25 '14 at 10:34
  • So you can just put the name in the prototype after parsing the JSON ? – DrakaSAN Sep 25 '14 at 10:40
  • Also, `object.__proto__` is deprecated, if Harmony is a option, you can use `Object.setPrototypeOf()`, but its slow too. – DrakaSAN Sep 25 '14 at 10:44
  • @DrakaSAN Thank you, I din't know that `__proto__` was deprecated. I may have to use `Object.setPrototypeOf()` as you suggest, though I would prefer a fast solution given the number of json objects involved. – Toaster Sep 25 '14 at 10:51
  • WTH do you mean by "the class does not exist"? Btw, the node environment is more capable than browser environments, so I wonder why any code would not work. – Bergi Sep 25 '14 at 12:03
  • @Bergi I mean that the prototype is not defined. – Toaster Sep 25 '14 at 13:04
  • @Colin: But if there is no prototype, there is no class, so what would you want to convert the plain object to at all? – Bergi Sep 25 '14 at 13:21

2 Answers2

0

I have an answer that makes some use of eval and __proto__. Eval is only used to create the first prototype.

// create prototype - called once
var on = 'Apple';
var estr = 'function ' + on + '() {} ' + on + '.prototype.getInfo = function() { return this.name; }; ';
eval.apply(global, [estr]);

// make a simple object from JSON:
// called many times 
var apl = JSON.parse('{ "name": "Jason" }');

// force its class to be Foo
apl.__proto__ = global[on].prototype;

// this method works
console.log(apl.getInfo());
Toaster
  • 1,911
  • 2
  • 23
  • 43
  • [`eval.apply` is rubbish](http://perfectionkills.com/global-eval-what-are-the-options/). Also, there's no reason to pollute the global namespace - and depending on where your `on` string comes from, this even might be a monstrous security issue. – Bergi Sep 25 '14 at 12:07
  • @Bergi AOK. Do you have a better solution? – Toaster Sep 25 '14 at 13:03
  • Why not just do `apl.getInfo = function() { return this.name; };` (maybe caching the function)? Even if you want to use `__proto__` for whatever reasons, I don't see any reason to create empty constructors, or even use `eval` to do so. – Bergi Sep 25 '14 at 13:23
  • @Bargi I don't see how `apl.getInfo = function() { return this.name; };` forces the object name. I.e., in the example I need to define a prototype with the name in `var on;`, in this case `Apple`. – Toaster Sep 25 '14 at 16:11
  • "Object names" as you call them are quite insignificant anyway, no program code would depend on them. Sure, to [get a named function](http://stackoverflow.com/q/9479046/1048572) you need to eval some code, but the function doesn't need to be in global scope for that. – Bergi Sep 25 '14 at 16:48
0

Maybe this?

var constructors = {
   "Obj1": ObjConstructor1(){},
   "Obj2": ObjConstructor2(){},
}
var obj = new constructors.Obj1();
var jsonObj = {"a":1,"b":2};

for (var x in jsonObj) {
  obj[x] = jsonObj[x];
}
vodolaz095
  • 6,680
  • 4
  • 27
  • 42
  • This may work. Can you call the constructor if the name of the 'class' were in a string? (without using a switch statement) – Toaster Sep 25 '14 at 18:32