Object.defineProperty 在原型上阻止 JSON.stringify 序列化它
Object.defineProperty on a prototype prevents JSON.stringify from serializing it
我正在使用 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 输出)。
我的实际问题是:这正常吗?
如果是这样,我该如何以最有效的方式解决它?
您可以在原型上定义一个 toJSON()
方法来自定义实例的序列化方式。
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) 将替换符 function/array 作为第二个参数传递给 JSON.stringify()。
来自原型的白名单属性:
JSON.stringify(instance, Object.keys(instance.constructor.prototype))
如果你想推进它,试试 TypeScript 的装饰器提案:
根据这个提议 (https://github.com/wycats/javascript-decorators):
装饰器是:
- 一个表达式
- 计算为一个函数
- 将目标、名称和 属性 描述符作为参数
- 和可选的returns一个属性描述符安装在目标对象上
它是这样的(高级视图):
客户代码:
@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
的存储库中
在这里放一些东西希望能帮助到别人。
我所做的修复 JSON.stringify 未序列化原型
上定义的属性
var newObject = $.extend(false, {}, orginalObj);
然后我注意到 newObject 具有实例属性而不是原型属性。
我正在使用打字稿并获取访问器。
我正在使用 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 输出)。
我的实际问题是:这正常吗?
如果是这样,我该如何以最有效的方式解决它?
您可以在原型上定义一个 toJSON()
方法来自定义实例的序列化方式。
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) 将替换符 function/array 作为第二个参数传递给 JSON.stringify()。
来自原型的白名单属性:
JSON.stringify(instance, Object.keys(instance.constructor.prototype))
如果你想推进它,试试 TypeScript 的装饰器提案:
根据这个提议 (https://github.com/wycats/javascript-decorators):
装饰器是:
- 一个表达式
- 计算为一个函数
- 将目标、名称和 属性 描述符作为参数
- 和可选的returns一个属性描述符安装在目标对象上
它是这样的(高级视图):
客户代码:
@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
的存储库中在这里放一些东西希望能帮助到别人。 我所做的修复 JSON.stringify 未序列化原型
上定义的属性var newObject = $.extend(false, {}, orginalObj);
然后我注意到 newObject 具有实例属性而不是原型属性。 我正在使用打字稿并获取访问器。