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:
- Copying AJAX JSON object into existing Object
- 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
Redirect a State to Default Substate with Ui-Router in Angularjs
How to Expose Iframe's Dom Using Jquery
JavaScript Associative Array to JSON
Template String as Object Property Name
Referencing "This" Inside Setinterval/Settimeout Within Object Prototype Methods
What Is Returned from a Constructor
How to Execute Promises Sequentially, Passing the Parameters from an Array
Caching a Promise Object in Angularjs Service
Recursive Matching with Regular Expressions in JavaScript
Variable Scope in D3 JavaScript
Chrome Extension - Sendresponse Not Waiting for Async Function
Doesn't JavaScript Support Closures with Local Variables
Get Local Ip Address in Node.Js