JavaScript 中如何让 JSON 格式化后的数据按指定的键名顺序排列?

如下一组 JSON 数据,我该如何让它按照我指定的 key 顺序进行排列。

[
    {
        "a": "1",
        "1": "2"
    },
    {
        "1": "a",
        "a": "b"
    }
]

如按照键名先 a1 的顺序,即得到如下格式化后的数据。

[
    {
        "a": "1",
        "1": "2"
    },
    {
        "a": "b",
        "1": "a"
    }
]
阅读 8.1k
6 个回答
//排序设置
var sortSet = {"c" : 0, "b" : 1, "a" : 2}

var myMap = new Map
myMap.set("a", "a")
myMap.set("b", "b")
myMap.set("c", "c")
//console.log(Array.from(myMap.keys()))

for (const key of Array.from(myMap.keys())) {
    const val = myMap.get(key);
    console.log(val)
}

myMap = new Map([...myMap].sort((a, b) => sortSet[a[0]]-sortSet[b[0]]))


for (const key of Array.from(myMap.keys())) {
    const val = myMap.get(key);
    console.log(val)
}

其实你不能获得这样的保证,因为你要排键名的是对象,对象在内存中存储时并没有稳定的键名顺序。

你最多在数组排序时,按元素对象某个属性进行排序。

已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。

对象是无序的,对他排序没有意义也做不到,但你可以在取值的时候按照某个顺序取

let sortkeys = ['a', '1']
sortkeys.forEach(item => {
    console.log(obj[item])
})
已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。

javascript里面的对象在对key迭代时有自己的输出顺序,而JSON.stringfiy的格式化顺序,就是按这个来的,如果想要指定格式化后key的顺序,就必须自己重写stringfiy逻辑,你可以参考下这个

问题:
(1) 需要多花出O(Array.Length)的时间复杂度给每个对象定义toJSON(可以接受的因为JSON.stringfiy的时间复杂度比这高好几倍)
(2) 由于自己实现的格式化逻辑需要,如果需要JSON.stringfiy那样的replacer,和自定义缩进的功能需要自己实现

/**
 * 自己定义的compre函数决定了key的输出顺序
 * @param {*} key1
 * @param {*} key2
 */
const compare = (key1, key2) => {
  //由于不可能有重复key所以不用考虑相等的情况
  const key1Priority = priority[key1];
  const key2Priority = priority[key2];

  if (typeof key1Priority === "number" && typeof key2Priority === "number") {
    //priority高的排在前,也就是降序排序
    return key2Priority - key1Priority;
  }

  if (key1 < key2) return -1;
  else return 1;
};

const toJSON = function () {
  const keys = Object.keys(this);
  keys.sort(compare);
  const entries = [];
  for (const key of keys) {
    entries.push(`"${key}": ${JSON.stringify(this[key])}`);
  }

  return "{" + entries.join(",") + "}";
};

for (let i = 0; i < temp.length; ++i) {
  temp[i].toJSON = toJSON;
  Object.defineProperty(temp[i], "toJSON", {
    enumerable: false,
    configurable: true,
    writable: true,
    value: toJSON
  });
}
console.log(JSON.stringify(temp));

虽然我不知道意义何在,但 ——

const data = [
    { "a": "1", "1": "2", b: 3 },
    { "1": "a", "a": "b", b: false }
];

// 未指定顺序
console.log(JSON.stringify(data));

// 用第 2 个参数指定顺序
console.log(JSON.stringify(
    data,
    ["b", "a", "1"]
));

结果

[{"1":"2","a":"1","b":3},{"1":"a","a":"b","b":false}]
[{"b":3,"a":"1","1":"2"},{"b":false,"a":"b","1":"a"}]

可以看到第 2 行的结果是按 ["b", "a", "1"] 的顺序

注意:

  1. 试验结果是没问题,但不知道跟 ECMAScript 实现有没得问题,会不会在不同的环境有不同的效果。
  2. stringify 的第二个参数作为数组时的本意是筛选属性,所以对于较复杂的 数组,可能处理起来会比较麻烦。

已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题