【问题标题】:`JSON.stringify` omits custom keys in array`JSON.stringify` 省略了数组中的自定义键
【发布时间】:2019-03-30 06:28:40
【问题描述】:

我将我的数组存储为数组、数组和对象的混合体。例如假设这个:

let arrObj = [];
arrObj["x"] = 12;
arrObj.push(12);
arrObj["y"] = 15;
arrObj.push(15);

// result: arrObj = [12, 15, x: 12, y: 15]

这样,即使使用arrObj[0] 和arrObj["x"],我也可以访问值12。这样一来,我就可以对其进行重复。

但是当我将它串起来时,x 和 y 键会丢失:

JSON.stringify(arrObj)
// result: "[12,15]"

我应该如何维护这些键和它们的值?

【问题讨论】:

  • 这不是一个有效的 JSON 字符串:"[ 12, 15, 'x': 12, 'y': 15 ]"。即使您输出它,您也无法将其解析为 JSON。因此,如果不进行某种转换,尚不清楚这如何工作。
  • 这足以让我使这个结构对我自己有效。我的意思是,在另一端,我自己正在捕捉价值,所以我也可以操纵那一端。
  • [...arrObj.values()] // [12, 15] 是实际结果。不要与 x 和 y 混淆。它们只是 arrObj 数组的属性
  • @ConductedClever Then Pranav C Balan's update answer using object is abt for your case
  • 当然是@AswinKumar。谢谢。

标签: javascript arrays json stringification


【解决方案1】:

在字符串化时使用spread syntax将其转换为对象,然后解析并使用Array#reduce方法生成数组。

数组保留属性,因为 Array 在 Javascript 中也是一个对象。

let arrObj = [];
arrObj["x"] = 12;
arrObj.push(12);
arrObj["y"] = 15;
arrObj.push(15);

let json = JSON.stringify({ ...arrObj });

console.log(json);

let parsed = Object.entries(JSON.parse(json)).reduce((arr, [key, value]) => (arr[key] = value, arr), []);

console.log(parsed);

仅供参考:但对于键值对数据,最好使用Object 或Map,而不是更好,这在我看来是正确的方式。


更新 1: 或者您可以使用一个主对象来保留所有附加属性,并在其中创建一个属性来保留数组。

let arrObj = {
  arr: []
};
arrObj["x"] = 12;
arrObj.arr.push(12);
arrObj["y"] = 15;
arrObj.arr.push(15);

let json = JSON.stringify(arrObj);

console.log(json);

let parsed = JSON.parse(json);

console.log(parsed);

更新 2: 如果您尝试设置名为 arr(在我的情况下)的属性,则第二种方法会导致问题,因此请将对象值保存在单独的属性中。

let arrObj = {
  arr: [],
  obj: {}
};
arrObj.obj["x"] = 12;
arrObj.arr.push(12);
arrObj.obj["y"] = 15;
arrObj.arr.push(15);

let json = JSON.stringify(arrObj);

console.log(json);

let parsed = JSON.parse(json);

console.log(parsed);

【讨论】:

  • 谢谢。 Map 擅长接受键值对和重复但不可序列化。
  • 第二种解决方案也不错,但它会破坏我的扩展方法:Array.prototype.pushNamed = function (key, value) { this[key] = value; this.push(value); return this; }
  • @ConductedClever :像Object.prototype.pushNamed = function (key, value) { this[key] = value; this.arr.push(value); return this; }一样重写它
  • @ConductedClever ;)
  • @ConductedClever :对于新方法,它就像Object.prototype.pushNamed = function (key, value) { this.obj[key] = value; this.arr.push(value); return this; }
【解决方案2】:

数组应该只包含数字索引值。如果除了值之外还需要 键,请使用对象:

const obj = {};
obj.x = 12;
obj[0] = 12;
obj.y = 15;
obj[1] = 15;

console.log(JSON.stringify(obj));

for (let i = 0; i in obj; i++) {
  console.log(obj[i]);
}

您还可以考虑使用同时包含数组和自定义键值对的对象,例如:

const arr = [];
const obj = { arr };
obj.x = 12;
obj.y = 15;
arr.push(12);
arr.push(15);

console.log(JSON.stringify(obj));

【讨论】:

  • 我希望它是一个数组,让 foreach 就可以了。这不是我的答案。
  • 如果要保留任意键而不是字符串化,请改用对象,然后在需要使用forEach时将其转换为数组。
  • 字符串化数组不能有任意键值对。如果您需要通过序列化保存任意键值对,则必须使用对象,而不是数组。
  • 如果你这样做,结果将不是有效的 JSON,并且除了你构建的自定义解析器之外,其他任何东西都无法解析,这将是一个困难和坏主意。
  • 如果它是自定义解析器,那么根据定义,您不会处理 JSON,因为 JSON 解析不起作用。此外,想要 foreach 数组是违反标准的错误理由。
【解决方案3】:

这是一个花哨的 1 班轮解决方案:

let arrObj = [];
    arrObj["x"] = 12;
    arrObj.push(12);
    arrObj["y"] = 15;
    arrObj.push(15);

var string = JSON.stringify(Object.keys(arrObj).reduce((acc, cur) => ((acc[cur] = arrObj[cur]), acc), {}));

console.log(string);

P.S:我认为值得一提的是,您可能会遇到意外行为,因为在 JS 中,无法保证对象属性是有序的(如您所愿)。 Does JavaScript Guarantee Object Property Order?

【讨论】:

  • 虽然顺序对我来说并不重要,但字符串化的对象并不如我所愿。谢谢。
猜你喜欢
  • 2021-06-05
  • 2022-07-07
  • 2019-09-01
  • 2020-01-19
  • 1970-01-01
  • 2018-06-08
  • 2020-05-04
  • 1970-01-01
  • 2014-11-21
相关资源
最近更新 更多