Javascript 原型上的Object.defineProperty阻止JSON.stringify序列化它
我正在使用TypeScript定义一些类,当我创建一个属性时,它会在以下命令中生成与Javascript 原型上的Object.defineProperty阻止JSON.stringify序列化它,javascript,json,typescript,Javascript,Json,Typescript,我正在使用TypeScript定义一些类,当我创建一个属性时,它会在以下命令中生成与Class1等价的命令: 序列化时,它不会输出我刚才定义的属性 instance2和instance3通过序列化定义的属性,表现出我所期望的行为。(参见plunkr输出) 我的实际问题是:这正常吗 如果是这样,我如何以最有效的方式解决它?您可以在原型上定义一个方法来自定义实例的序列化方式 Class1.prototype.toJSON = function () { return { N
Class1
等价的命令:
序列化时,它不会输出我刚才定义的属性
instance2
和instance3
通过序列化定义的属性,表现出我所期望的行为。(参见plunkr输出)
我的实际问题是:这正常吗
如果是这样,我如何以最有效的方式解决它?您可以在原型上定义一个方法来自定义实例的序列化方式
Class1.prototype.toJSON = function () {
return {
Name: this.Name
};
};
JSON.stringify(new Class1()); // Will be '{"Name":"test1"}'
正如您所发现的,它不会序列化在原型上定义的属性 我知道这并不理想,但另一个选择是:
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
});
}
}
在实例上定义属性将序列化属性。是的,它是按设计的
按照ECMA中的定义,只有自己的可枚举属性被序列化(stringify()
是根据Object.keys()
等定义的)
属性访问器是在TypeScript和ES6中的原型上定义的
回答你的最后一个问题,这是执行此操作最有效的方法
除此之外,只有a)为序列化的每个对象部分定义一个toJSON(),或者b)将替换函数/数组作为第二个参数传递给JSON.stringify()
原型的白名单属性:
JSON.stringify(instance, Object.keys(instance.constructor.prototype))
如果您想推动它向前发展,请为TypeScript提供一个“尝试装饰”方案: 根据这项建议(): 装饰师是:
- 表情
- 它的计算结果是一个函数
- 它将目标、名称和属性描述符作为参数
- 并可选地返回要安装在目标对象上的属性描述符
@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;
}
}
更新:我将这个示例decorator提取到一个位于的存储库中,希望在这里放置一些可以帮助其他人的东西。 我为fix JSON.stringify所做的不是序列化原型上定义的属性
var newObject = $.extend(false, {}, orginalObj);
然后我注意到newObject具有实例属性而不是原型属性。
我正在使用typescript和get accessor。我将此标记为答案,因为我最终实现了toJSON。我已经有了私有成员到公共属性的映射,因为我正在使用它将一些JSON从API映射到我的TypeScript类。在toJson方法中,我只需使用该映射创建一个新对象,该对象的所有属性都使用倒置的名称。我很快就会在博客上发表。我已经考虑过这个问题,但我想要一个使用TypeScript本身的解决方案。@ChristianDroulers是的,我也不会使用这个解决方案:)。。。添加一个toJSON方法是一个更好的选择。我很快会在博客上写的。很有趣!但在短期内,这不是一个可行的解决方案。谢谢是的,你说得对,但我觉得它很有前途,希望在生产中使用它soon@Jacks也许您是在使用类作为键而不是类的原型进行检索?我用一个有效的实现更新了我的答案,请看一看。@AndréWerlang非常感谢您的更新。是的,我确实是第一次尝试通过传递类而不是原型来检索值。但是为了验证,我试图打印整个WeakMap,这是不可能的,因为其中的键不可枚举(请参阅)。感谢您在几年后澄清此帖子:)@Apidcloud,类似这样的内容(注意我删除了块,此代码不会运行,但我添加了箭头以显示
ClassDecorator
和propertydcorator
var newObject = $.extend(false, {}, orginalObj);