EDIT (2018-12-15): Fixed an issue with the answer.
> I'd like to see an example where an object is defined through a prototype member function […]
I'm not entirely sure what you're asking for—probably because I'm lacking the context.
> […] what tasks prototype.clone() and prototype.toJSON() have to carry out in order to serialize and deserialize these objects.
A custom object instance's clone() method simply needs to return a clone of the instance, whatever that happens to mean for the custom object in question.
A custom object instance's toJSON() method needs to return code string that when evaluated will return a clone of the instance.
In both cases, since the end goal is roughly the same, this means creating a new instance of the base class/object and populating it with copies/clones of the relevant data. There is no one size fits all example for either of these methods because its the properties of the instance which determine what you need to do.
That said, you already have one example from the item Q&A you linked. Here's another simple one whose constructor takes a config/option object:
window.ContactInfo = function (contactInfoObj) {
// Set up our own data properties with some defaults.
this.name = '';
this.address = '';
this.phone = '';
this.email = '';
// Copy details from the given contact info object.
Object.assign(this, contactInfoObj);
};
ContactInfo.prototype.clone = function () {
// Return a new instance containing our current data.
return new ContactInfo(this);
};
ContactInfo.prototype.toJSON = function () {
// Return a code string that will create a new instance
// containing our current data.
//
// NOTE: Do not use `this` directly or you'll trigger
// out of control recursion. Make a copy of the own
// properties instead.
var data = Object.assign({}, this);
return JSON.reviveWrapper('new ContactInfo($ReviveData$)', data);
};
The usage would be something like:
<<set $Joe to new ContactInfo({
name : 'Joe Blow',
phone : '1 555 555 1212',
email : 'joe@blow.com'
})>>
Here's the same basic example but whose constructor takes discrete parameters instead:
window.ContactInfo = function (name, addr, phone, email) {
// Set up our own data properties with some defaults.
this.name = name || '';
this.address = addr || '';
this.phone = phone || '';
this.email = email || '';
};
ContactInfo.prototype.clone = function () {
// Return a new instance containing our current data.
return new ContactInfo(
this.name,
this.address,
this.phone,
this.email
);
};
ContactInfo.prototype.toJSON = function () {
// Return a code string that will create a new instance
// containing our current data.
return JSON.reviveWrapper(String.format(
'new ContactInfo({0},{1},{2},{3})',
JSON.stringify(this.name),
JSON.stringify(this.address),
JSON.stringify(this.phone),
JSON.stringify(this.email)
));
};
The usage would be something like:
<<set $Joe to new ContactInfo(
'Joe Blow',
'',
'1 555 555 1212',
'joe@blow.com'
)>>
> What are the most complicated objects to serialize? How does one approach a problem like that?
In general, Purple or Green makes no difference. It's less about difficulty and more about the amount of work you have to do.
That said, I'd say that the most complicated custom classes/objects are:
- Those whose constructors take many discrete arguments, rather than a config/option object, since you won't be able to use data parameter to JSON.reviveWrapper(). Having to encode them all in the code string can be a pain.
- Any you didn't write yourself, for two reasons. The first being that you'll have to learn what data needs to be copied. The second being writing the two methods and injecting them into its prototype—not that the latter part is hard is most cases.
EDIT (2018-12-15): Fixed an issue with the answer.