将具有 toJSON 方法的对象数组序列化为 JSON 时出现奇怪错误
Strange error when serializing to JSON an array of objects which have a toJSON method
我使用 NSwag 为 swagger API 端点生成 TypeScript 类型和 classes。生成的 classes 包含每个对象的 .toJSON()
方法,在使用 JSON.stringify()
.
将对象序列化为 JSON 时调用该方法
序列化单个对象时一切正常,但当我尝试序列化对象数组时,它抛出一个奇怪的错误:
angular.js:14199 TypeError: Cannot create property 'code' on string '0'
at Dashboard.toJSON (App/models/api.js:785:34)
at JSON.stringify (<anonymous>)
触发它的代码非常简单:
console.log(JSON.stringify([
Dashboard.fromJS({
code: "1212312",
name: "tresads",
description: "some description"
}),
Dashboard.fromJS({
code: "1212312",
name: "tresads",
description: "some description"
})
]));
摘录class:
export class Dashboard implements IDashboard {
code?: string | undefined;
...
constructor(data?: IDashboard) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(data?: any) {
if (data) {
this.code = data["code"];
...
}
}
static fromJS(data: any): Dashboard {
let result = new Dashboard();
result.init(data);
return result;
}
toJSON(data?: any) {
data = data ? data : {};
data["code"] = this.code;
...
return data;
}
clone() {
const json = this.toJSON();
let result = new Dashboard();
result.init(json);
return result;
}
}
知道为什么 JSON.stringify()
使用“0”参数调用 toJSON()
方法吗?
方法 toJSON
将使用一个参数调用,即分配给 this
的 属性 名称。本质上,你感兴趣的值不是那个参数,而是 this
,它将绑定到你可以转换的值。由于您使用数组调用 stringify
,因此将使用该数组的可枚举属性调用 toJSON
,即 0
和 1
,而 this
将是相应的 Dashboard 对象。
此外,我的印象是您可以充分利用 Object.assign
,它将属性从一个对象复制到另一个对象,这实际上就是您在构造函数的 for
循环中所做的。
所以这就是你如何做到的。我去掉了打字稿修饰,使用了普通的JavaScript,但是原理还是一样的:
class Dashboard {
constructor(data) {
// Object.assign does essentially what you want with the loop:
Object.assign(this, data);
}
init(data) {
return Object.assign(this, data);
}
static fromJS(data) {
return new Dashboard(data);
}
toJSON(key) {
// `key` is the key/index of the property in the parent object.
// That probably is of no interest to you. You need `this`.
// Extract properties into plain object, and return it for stringification
return Object.assign({}, this);
}
clone() {
return new Dashboard(this);
}
}
console.log(JSON.stringify([
Dashboard.fromJS({
code: "1212312",
name: "tresads",
description: "some description"
}),
Dashboard.fromJS({
code: "1212312",
name: "tresads",
description: "some description"
})
]));
实际上,在给定的示例中,您根本不需要 toJSON
,因为 Dashboard 实例的属性是可枚举的,因此无论如何它们都会被字符串化。如果出于某种原因你确实需要它来进行某种转换,那么当然你仍然需要包含该转换的逻辑,因为 Object.assign
只是一个简单的副本。
我使用 NSwag 为 swagger API 端点生成 TypeScript 类型和 classes。生成的 classes 包含每个对象的 .toJSON()
方法,在使用 JSON.stringify()
.
序列化单个对象时一切正常,但当我尝试序列化对象数组时,它抛出一个奇怪的错误:
angular.js:14199 TypeError: Cannot create property 'code' on string '0'
at Dashboard.toJSON (App/models/api.js:785:34)
at JSON.stringify (<anonymous>)
触发它的代码非常简单:
console.log(JSON.stringify([
Dashboard.fromJS({
code: "1212312",
name: "tresads",
description: "some description"
}),
Dashboard.fromJS({
code: "1212312",
name: "tresads",
description: "some description"
})
]));
摘录class:
export class Dashboard implements IDashboard {
code?: string | undefined;
...
constructor(data?: IDashboard) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}
init(data?: any) {
if (data) {
this.code = data["code"];
...
}
}
static fromJS(data: any): Dashboard {
let result = new Dashboard();
result.init(data);
return result;
}
toJSON(data?: any) {
data = data ? data : {};
data["code"] = this.code;
...
return data;
}
clone() {
const json = this.toJSON();
let result = new Dashboard();
result.init(json);
return result;
}
}
知道为什么 JSON.stringify()
使用“0”参数调用 toJSON()
方法吗?
方法 toJSON
将使用一个参数调用,即分配给 this
的 属性 名称。本质上,你感兴趣的值不是那个参数,而是 this
,它将绑定到你可以转换的值。由于您使用数组调用 stringify
,因此将使用该数组的可枚举属性调用 toJSON
,即 0
和 1
,而 this
将是相应的 Dashboard 对象。
此外,我的印象是您可以充分利用 Object.assign
,它将属性从一个对象复制到另一个对象,这实际上就是您在构造函数的 for
循环中所做的。
所以这就是你如何做到的。我去掉了打字稿修饰,使用了普通的JavaScript,但是原理还是一样的:
class Dashboard {
constructor(data) {
// Object.assign does essentially what you want with the loop:
Object.assign(this, data);
}
init(data) {
return Object.assign(this, data);
}
static fromJS(data) {
return new Dashboard(data);
}
toJSON(key) {
// `key` is the key/index of the property in the parent object.
// That probably is of no interest to you. You need `this`.
// Extract properties into plain object, and return it for stringification
return Object.assign({}, this);
}
clone() {
return new Dashboard(this);
}
}
console.log(JSON.stringify([
Dashboard.fromJS({
code: "1212312",
name: "tresads",
description: "some description"
}),
Dashboard.fromJS({
code: "1212312",
name: "tresads",
description: "some description"
})
]));
实际上,在给定的示例中,您根本不需要 toJSON
,因为 Dashboard 实例的属性是可枚举的,因此无论如何它们都会被字符串化。如果出于某种原因你确实需要它来进行某种转换,那么当然你仍然需要包含该转换的逻辑,因为 Object.assign
只是一个简单的副本。