`JSON.stringify` 在数组中忽略自定义键

4

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

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的内容。这样,我就可以对它进行循环。

但是当我将其转换为字符串时,键xy就会丢失:

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

我该如何维护这些键及其对应的值?

1
这不是一个有效的JSON字符串:"[ 12, 15, 'x': 12, 'y': 15 ]"。即使你输出它,也无法将其解析为JSON。因此,如果没有某种形式的转换,它是无法正常工作的。 - Mark
这对我来说已经足够让这个结构对自己有效了。我的意思是,在另一端,我自己捕捉这个值,这样我也可以操纵那一端。 - ConductedClever
[...arrObj.values()] // [12, 15] 是实际结果。不要与 x 和 y 混淆,它们只是 arrObj 数组的属性。 - User863
@AswinKumar 我想要 xy 以便将来直接访问。 - ConductedClever
1
@ConductedClever,那么Pranav C Balan的更新答案使用对象是适用于您的情况。 - User863
1
当然,@AswinKumar。谢谢。 - ConductedClever
3个回答

4
在字符串化时,使用扩展语法将其转换为对象,然后解析并使用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);

注意:对于键值对数据,最好使用ObjectMap,我认为这是正确的做法。


更新 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在接受键值对和重复方面很好,但不可序列化。 - ConductedClever
第二种解决方案也不错,但它会破坏我的扩展方法:Array.prototype.pushNamed = function (key, value) { this[key] = value; this.push(value); return this; } - ConductedClever
@ConductedClever:将其重写为 Object.prototype.pushNamed = function (key, value) { this[key] = value; this.arr.push(value); return this; } - Pranav C Balan
@ConductedClever ;) - Pranav C Balan
@ConductedClever:对于这种新方法,它应该是这样的 Object.prototype.pushNamed = function (key, value) { this.obj[key] = value; this.arr.push(value); return this; } - Pranav C Balan
让我们在聊天中继续这个讨论 - Pranav C Balan

0

数组应仅包含数字索引值。如果您想要添加键(key)除了值(value),请使用对象(object):

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。这不是我的答案。 - ConductedClever
1
字符串化的数组不能具有任意键值对。如果您需要在序列化期间保存任意键值对,则必须使用对象而不是数组。 - CertainPerformance
现在答案变得更好了。那么,如何操作 JSON.stringify 本身以允许任意键值对呢? - ConductedClever
1
如果这样做,结果将不是有效的JSON,并且除了您构建的自定义解析器之外,任何东西都无法解析它,这将是困难和不明智的。 - CertainPerformance
1
如果它是一个自定义解析器,那么根据定义,你不会处理JSON,因为JSON解析器无法工作。此外,想要对数组进行foreach循环是打破标准的不良理由。 - VLAZ
显示剩余5条评论

0

这里有一个花哨的一行代码解决方案:

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);

顺便提一下,你可能会遇到意外的行为,因为在JS中,不能保证对象属性的顺序(就像你想要的那样)。 JavaScript是否保证对象属性顺序?


虽然顺序对我来说并不重要,但字符串化的对象并不如预期。谢谢。 - ConductedClever

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接