我正在使用TypeScript来定义一些类,当我创建一个属性时,它会在以下plunkr中生成等效于Class1
的内容:
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"}"
序列化时,它不会输出我刚刚定义的属性。
通过序列化已定义的属性, instance2
和instance3
的行为与我期望的一样。 (参见plunkr输出)。
我的实际问题是:这是正常的吗?
如果是这样,我该如何以最有效的方式解决这个问题?
答案 0 :(得分:19)
您可以在原型上定义toJSON()
方法,以自定义实例的序列化方式。
Class1.prototype.toJSON = function () {
return {
Name: this.Name
};
};
JSON.stringify(new Class1()); // Will be '{"Name":"test1"}'
答案 1 :(得分:16)
如果您想推进它,请尝试针对TypeScript的装饰器提案:
根据此提案(https://github.com/wycats/javascript-decorators):
装饰者是:
就像这样(高级视图):
客户代码:
@serializable()
class Person {
constructor(name: string) {
this._name = name;
}
private _name: string;
@serialize()
get name() {
return this._name;
}
@serialize('Language')
get lang() {
return 'JavaScript';
}
}
基础设施:
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;
}
}
更新:我将此样本装饰器提取到https://github.com/awerlang/es-decorators
的存储库中答案 2 :(得分:7)
是的,这是设计的。
根据ECMA的定义,只有拥有的可枚举属性被序列化(stringify()
是根据Object.keys()
定义的。
属性访问器在原型上定义,包括TypeScript和ES6。
回答你的上一个问题,这是执行此操作的最有效方法。
除此之外,只有a)为序列化的每个对象部分定义toJSON(),或b)将替换器函数/数组作为第二个参数传递给JSON.stringify()。
原型中的白名单属性:
JSON.stringify(instance, Object.keys(instance.constructor.prototype))
答案 3 :(得分:1)
正如您所发现的那样,它不会序列化在原型上定义的属性。
我知道这不太理想,但另一种选择是这样做:
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
});
}
}
在实例上定义属性将序列化属性。