I'm XuéChūn - Javascript
type: channel
link: https://www.xuechun.vip/tag/Javascript/
items: JS保持JSON中读取顺序一致的方法

JS保持JSON中读取顺序一致的方法
type: item
date: 2025-04-16T00:58:00+00:00
description: 昨天临时写个小脚本，表单内容保存到JSON中，需要按照写入顺序读取。JS无法直接做到写入和读取顺序一致。本人能力有限，只能想到3种方法，每种方法适用场景不同，要根据前后端需求选择。一、JSON对象保存成JSON数组。把键值对拆分开，每个键值对单独保存到每个数组项上，利用数组保证顺序的一致性。{ "name": "米米奇", "age": 24, "city": "仓群峡谷" }保存成如下格式：[ {"name": "米米奇"}, {"age": 24}, {"city": "仓群峡谷"} ]但这个方法遍历起来很麻烦，因为js遍历时JSON对象时，必须要对key循环。另外查找也很麻烦，不能直接用in操作符，需要遍历数组，再逐项对比key才可以。arr.forEach(obj=>{ for(let key in obj){ if(key=="name"){ …… } } });优点：可以保证插入顺序。反序列化和序列化后顺序不变。反序列化后文件体积增加不大。缺点：遍历查找困难。二、对JSON数组进行改进。为了解决第一个方法中遍历和查找困难问题，修改一下数据结构：[ {key: "name", value: "米米奇"}, {key: "age": value: 24}, {key: "city": value: "仓群峡谷"} ]明确定义键值对的名称，这样每个数组项遍历和查找时，就可以用key直接定位，不需要嵌套循环了。arr.forEach(obj=>{ if(obj.key=="name"){ …… } });代码相对与第一个确实简单多了。优点：可以保证插入顺序。反序列化和序列化后顺序不变。遍历查找相对简单。缺点：反序列化后文件体积变大，尤其值主要为数字时。需要约定好key-value项的名称。三、其他方法。用额外数组记录key的顺序，暴露给外部自定义的方法（getter、setter、forEach、delete等），但是这样代码要改动好多，原生方法都不能用了，还要维护调用接口，数据一致性难以确保。不推荐自己造轮子。如果无反序列化要求，可以利用ES6 Proxy代理，记录JSON对象的插入、修改操作，内部数组记录key的顺序，遍历时直接返回内部保存的key数组。直接上代码：/** * 用于代理实现json遍历顺序和插入时一致 * 用法：var proxy = JSONProxy(); * 然后可以直接用原生方法操作，for(key in obj){}遍历时key就是添加顺序 * 注意：重新赋值时，会把key移到末尾，如果不需要可以修改代码 */ function JSONProxy(obj){ return new Proxy(obj||{}, { // 用于保存健的插入顺序 keys:[], //设置属性时，检测并保存key，这里其实有两种算法，看需求 set: function(target, key, value, receiver){ let index=this.keys.indexOf(key); if(index>=0){ this.keys.splice(index,1); // 删除已有健 } this.keys[this.keys.length]=key; // 添加到末尾 return target[key]=value; }, // 拦截属性删除操作 deleteProperty:function(target, key) { let index=this.keys.indexOf(key); if(index>=0){ this.keys.splice(index,1); } return delete target[key]; }, // 遍历获取键值时的操作，for...in循环，返回一个数组。 ownKeys:function(target){ return this.keys; } }); }因为使用了代理，修改一下变量定义外，现有代码再不需要改动。代码：let wuta={}; let person=JSONProxy(wuta); // 赋值 person.name="小虾米" person.country="萌国"; person.city="葫芦岛"; // 循环遍历 for(let key in person){ …… // key顺序'name', 'country','city' } // 获取所有key数组。 let keys=Object.keys(person); // 输出 ['name', 'country', 'city'] // 或者 let keys=Object.getOwnPropertyNames(person); // 上面无法获取内部属性了，JSON也不…