Casting Plain Objects to Class Instances in JavaScript

Casting plain objects to class instances in javascript

Creating an object in JavaScript requires the invocation of its constructor. So, at first you will need to find the correct arguments, which may not always be just properties. After that, you can reassign all public properties from the JSON-parsed object to the created instances.

A general solution would be that every constructor accepts any objects that look like instances (including real instances) and clones them. All the internal logic needed to create proper instances will be located in the right place then.

Or even better than overloading the constructor might be to create a static method on your class that takes objects and creates instances from them:

Person.fromJSON = function(obj) {
// custom code, as appropriate for Person instances
// might invoke `new Person`
return …;
};

Your case is very simple, as you don't have any arguments and only public properties. To change {personName:John,animals:[]} to an object instance, use this:

var personLiteral = ... // JSON.parse("...");
var personInstance = new Person();
for (var prop in personLiteral)
personInstance[prop] = personLiteral[prop];

You can also use Object.assign functionality (or e.g. jQuery.extend pre-ES6) for this:

var personInstance = Object.assign(new Person(), personLiteral);

The creation of the Animal instances works analogous.

As JSON does not transport any information about the classes, you must know the structure before. In your case it will be:

var persons = JSON.parse(serverResponse);
for (var i=0; i<persons.length; i++) {
persons[i] = $.extend(new Person, persons[i]);
for (var j=0; j<persons[i].animals; j++) {
persons[i].animals[j] = $.extend(new Animal, persons[i].animals[j]);
}
}

Btw, your run methods seems likely to be added on the Animal.prototype object instead of each instance.

How to cast a plain object as a instance of another type in JavaScript

Session looks to be exported only from session.ts. The constructor is empty, so that's not something you have to worry about, it's just an object with properties. To turn a non-Session into a Session, you should be able to just assign to properties of a Session.

import { Session } from "@shopify/shopify-api/dist/auth/session/session";

function loadCallback(id) {
console.log("loadCallback ", id);
return Object.assign(
new Session(),
JSON.parse(fs.readFileSync("./session.json", "utf8")))
);
}

Create class instance from plain object without manual constructor

After passing the object, use Object.assign to assign all of its properties to the instantiation:

class Person {  id;  firstName;  lastName;  age;  constructor(plainObject) {    Object.assign(this, plainObject);  }  fullName() {    return `${this.firstName} ${this.lastName}`;  }}
const hemmingway = { id: 1, firstName: "Ernest", lastName: "Hemmingway", age: 62};const personHemmingway = new Person(hemmingway);console.log(personHemmingway.fullName());

How do I cast a JSON Object to a TypeScript class?

You can't simple cast a plain-old-JavaScript result from an Ajax request into a prototypical JavaScript/TypeScript class instance. There are a number of techniques for doing it, and generally involve copying data. Unless you create an instance of the class, it won't have any methods or properties. It will remain a simple JavaScript object.

While if you only were dealing with data, you could just do a cast to an interface (as it's purely a compile time structure), this would require that you use a TypeScript class which uses the data instance and performs operations with that data.

Some examples of copying the data:

  1. Copying AJAX JSON object into existing Object
  2. Parse JSON String into a Particular Object Prototype in JavaScript

In essence, you'd just :

var d = new MyRichObject();
d.copyInto(jsonResult);

javascript: casting an object that has been created with eval

There is no concept of casting in JavaScript. Instead, you can modify your class' constructor to accept a plain object. How you do this depends on how you've set up your class, but could simply involve a shallow copy of the object into a new instance of the class:

var MyClass = function (obj) {
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
this[i] = obj[i];
}
// Other class initialisation code
};

Then "cast" your object like this:

var result = new MyClass(someObject);

If you have multiple classes that require this, you may prefer to create an extend function that does the cloning for you (or if you're using jQuery, this function already exists):

var extend = function (obj1, obj2) {
for (var i in obj2) {
if (!obj2.hasOwnProperty(i)) continue;
obj1[i] = obj2[i];
}
};

And then "cast" like this:

var result = new MyClass();
extend(result, someObject);

How to serialize an object and cast it back to the same class as the original object

when you serialize an object you trigger the toString or the toJSON method of your class' instance and end up with just a "dumb" JSON representation of your enumerable attributes.

if you want to recreate an instance that behaves like it did prior to serialisation, you will need to set an extra key/value pair in your toJSON function like ___internalType: 'state' and then later use eg. a switch statement to recreate your specific class with the new MyClass(serializedData)and passing in your serialised instance. Within the constructor of your class, you set all the attributes you need and voilà, you have your "old" instance again

/edit: to clarify the reason why your console logs aren't showing up is because you are not recreating an instance of your class but just creating a new plain Object.

Convert javascript class instance to plain object preserving methods

Ok, so the implementation in my OP was wrong, and the mistake was simply stupid.

The correct implementation when using es6 is:

toJSON(proto) {
let jsoned = {};
let toConvert = proto || this;
Object.getOwnPropertyNames(toConvert).forEach((prop) => {
const val = toConvert[prop];
// don't include those
if (prop === 'toJSON' || prop === 'constructor') {
return;
}
if (typeof val === 'function') {
jsoned[prop] = val.bind(jsoned);
return;
}
jsoned[prop] = val;
});

const inherited = Object.getPrototypeOf(toConvert);
if (inherited !== null) {
Object.keys(this.toJSON(inherited)).forEach(key => {
if (!!jsoned[key] || key === 'constructor' || key === 'toJSON')
return;
if (typeof inherited[key] === 'function') {
jsoned[key] = inherited[key].bind(jsoned);
return;
}
jsoned[key] = inherited[key];
});
}
return jsoned;
}


Related Topics



Leave a reply



Submit