J'utilise TypeScript pour définir certaines classes et lorsque je crée une propriété, cela génère l'équivalent de Class1
dans le fichier plunkr suivant:
http://plnkr.co/edit/NXUo7zjJZaUuyv54TD9i?p=preview
var Class1 = function () {
this._name = "test1";
}
Object.defineProperty(Class1.prototype, "Name", {
get: function() { return this._name; },
set: function(value) { this._name = value; },
enumerable: true
});
JSON.stringify(new Class1()); // Will be "{"_name":"test1"}"
Lors de la sérialisation, la propriété que je viens de définir n'est pas sortie.
instance2
et instance3
se comportent comme prévu en sérialisant la propriété définie. (voir la sortie plunkr).
Ma vraie question est: Est-ce normal?
Si oui, comment puis-je le contourner de la manière la plus efficace?
Vous pouvez définir une méthode toJSON()
sur votre prototype pour personnaliser le mode de sérialisation des instances.
Class1.prototype.toJSON = function () {
return {
Name: this.Name
};
};
JSON.stringify(new Class1()); // Will be '{"Name":"test1"}'
Si vous aimez le faire avancer, essayez la proposition de décorateurs pour TypeScript:
Selon cette proposition ( https://github.com/wycats/javascript-decorators ):
Un décorateur est:
Cela va comme ceci (vue de haut niveau):
Code client:
@serializable()
class Person {
constructor(name: string) {
this._name = name;
}
private _name: string;
@serialize()
get name() {
return this._name;
}
@serialize('Language')
get lang() {
return 'JavaScript';
}
}
Infrastructure:
const serialized = new WeakMap();
export function serializable(name?: string) {
return function (target, propertyKey, descriptor) {
target.prototype.toJSON = function () {
const map = serialized.get(target.prototype);
const props = Object.keys(map);
return props.reduce((previous, key) => {
previous[map[key]] = this[key];
return previous;
}, {});
}
}
}
export function serialize(name?: string) {
return function (target, propertyKey, descriptor) {
let map = serialized.get(target);
if (!map) {
map = {};
serialized.set(target, map);
}
map[propertyKey] = name || propertyKey;
}
}
UPDATE: J'ai extrait cet exemple de décorateur dans un référentiel situé à https://github.com/awerlang/es-decorators
Oui, c'est par conception.
Comme défini dans ECMA, seuls propres propriétés énumérables sont sérialisés (stringify()
est défini en termes de Object.keys()
, entre autres).
Les accesseurs de propriétés sont définis sur des prototypes, à la fois dans TypeScript et ES6.
Et pour répondre à votre dernière question, c’est le moyen le plus efficace d’effectuer cette opération.
À côté de cela, seulement a) définissant un toJSON () pour chaque objet faisant partie de la sérialisation, ou b) transmettant une fonction/un tableau de remplacement en tant que deuxième argument à JSON.stringify ().
Liste blanche des propriétés du prototype:
JSON.stringify(instance, Object.keys(instance.constructor.prototype))
Mettre quelque chose ici, espérons-le, peut aider les autres. Ce que j'ai à faire pour corriger JSON.stringify ne sérialise pas les propriétés définies sur le prototype
var newObject = $.extend(false, {}, orginalObj);
alors, je remarque que newObject a des propriétés d’occurrence plutôt que des propriétés de prototype. J'utilise TypeScript et get accessor.
Comme vous l'avez découvert, les propriétés définies sur le prototype ne seront pas sérialisées.
Je sais que ce n'est pas idéal, mais une autre option est de faire ceci:
class Class1 {
private _name = "test1";
Name: string; // do this to make the compiler happy
constructor() {
Object.defineProperty(this, "Name", {
get: function() { return this._name; },
set: function(value) { this._name = value; },
enumerable: true
});
}
}
Définir la propriété sur l'instance sérialisera la propriété.