JavaScript新手求助:JSON.stringify输出异常但对象含有效数据
嘿,我刚入门JS的时候也踩过类似的坑,结合你的描述,大概率是这几个原因之一,一个个给你拆解明白:
1. 你给数组添加了自定义属性,JSON.stringify会直接忽略它们
这是最符合你场景的情况:你的myObject是一个数组,里面的每个元素也是数组,然后你给这些子数组加了ArmyName这类自定义字符串键属性。
举个完全匹配你问题的例子:
// 模拟你的数据结构 const myObject = []; // 先往数组里push9个空数组 for(let i=0; i<9; i++){ myObject.push([]); } // 给第一个子数组添加自定义属性 myObject[0].ArmyName = "ARMY_1"; console.log(myObject); // 控制台会显示子数组带有ArmyName属性 console.log(JSON.stringify(myObject)); // 输出 [[],[],[],[],[],[],[],[],[]] myObject[0].ArmyName; // 能正常拿到"ARMY_1"
为啥会这样?因为JSON.stringify处理数组时,只会序列化数字索引对应的元素,完全忽略字符串键的自定义属性。数组本质是特殊对象,但JSON规范里数组是有序的值列表,非数字键的属性不在序列化范围内。
解决办法:别用数组存这类带自定义属性的数据,改成普通对象就行:
const myObject = []; for(let i=0; i<9; i++){ // 用普通对象代替数组 myObject.push({}); } myObject[0].ArmyName = "ARMY_1"; JSON.stringify(myObject); // 输出 [{"ArmyName":"ARMY_1"},{},{},{},{},{},{},{},{}]
2. 对象的属性是不可枚举的
如果你的数据存在普通对象里,但ArmyName是不可枚举属性,JSON.stringify也会跳过它。
比如用Object.defineProperty定义的属性,默认就是不可枚举的:
const myObject = [{}]; Object.defineProperty(myObject[0], 'ArmyName', { value: "ARMY_1", enumerable: false // 这个参数默认就是false }); console.log(myObject); // 控制台能看到ArmyName(因为console会显示所有属性) JSON.stringify(myObject); // 输出 [{}] myObject[0].ArmyName; // 正常拿到值
解决办法:要么把属性改成可枚举的,要么手动收集属性来序列化:
// 方法1:定义时设置enumerable为true Object.defineProperty(myObject[0], 'ArmyName', { value: "ARMY_1", enumerable: true }); // 方法2:手动构建要序列化的对象 const serializableData = myObject.map(item => ({ ArmyName: item.ArmyName })); JSON.stringify(serializableData);
3. 循环引用导致JSON.stringify返回Null
如果你的对象存在循环引用(比如obj.self = obj),JSON.stringify无法处理这种情况,会直接返回null。比如:
const army = { ArmyName: "ARMY_1" }; army.self = army; const myObject = [army]; console.log(myObject); // 控制台能显示数据(会标注循环引用) JSON.stringify(myObject); // 输出 null myObject[0].ArmyName; // 正常拿到值
解决办法:初学阶段建议先避免在数据里出现循环引用;如果必须处理,可以手动排除循环引用的属性,或者用专门处理循环引用的工具库。
4. console.log的“延迟显示”坑(概率较低)
有时候控制台显示的对象是实时状态,而你调用JSON.stringify的时候,数据还没被填充。比如异步加载的数据,你在请求完成前就执行了JSON.stringify,但之后console.log的时候数据已经加载完成,所以看起来console有数据但stringify是空的。
不过你说直接访问myObject[0].ArmyName能拿到值,说明数据已经存在了,这个情况概率比较低,但也可以排查:在调用JSON.stringify之前,先打印myObject[0].ArmyName确认值已经存在。
内容的提问来源于stack exchange,提问作者Rackover

