【问题标题】:Javascript recursively order object and nested objects as well as arraysJavascript递归排序对象和嵌套对象以及数组
【发布时间】:2016-03-05 08:16:07
【问题描述】:

我试图在启用按键排序的情况下获得与 pythons json.dumps() 相同的结果。这是作为 Postman 生成请求哈希的预请求脚本执行的。输出需要排序为有效的 json,用作散列的输入。我是 javascript 新手,看到许多旧答案声称无法对 javascript 中的对象进行排序。然而,必须有一个解决方案来生成给定标准的哈希。

  • 无法更改对象结构。
  • 只需要支持Chrome即可。
  • 我可以使用库。
  • requestParams 可以包含需要按任意深度排序的嵌套对象和数组。

这是我当前的代码。在 Chrome 控制台中,sortedResult 的对象预览是未排序的,但是当我展开对象和子对象时,Chrome 控制台将 sortedResult 显示为已排序,这正是它应该的方式。这给我的印象是 sortObject 正在工作。但是 requestOrdered 返回有效的 json 对象,但未排序。我最初的想法是 JSON.stringify() 可能正在对其进行排序。

const requestRebuilt = {"username": user, "password": password, "sTime": time, "function": function,
                 "functionParams": requestParams, "salt": salt};

function sortObject(object){  
    var keys = _.keys(object);
    var sortedKeys = _.sortBy(keys, function(key){  
        //console.log(key);
        return key; 
    });
    var sortedObj = {};
    var sortedObjJson = "";

    for(var index in keys){
        var key = keys[index];
        //console.log(key + ' ' + typeof object[key]);

        if(typeof object[key] == 'object' && !(object[key] instanceof Array)){
            sortedObj[key] = sortObject(object[key]);
        } else if(object[key] instanceof Array) {
            //sortedObj[key] = object[key].sort();
            var arrayLength = object[key].length;
            for (var i = 0; i < arrayLength; i++) {
                sortedObj[key] = sortObject(object[key][i]);
                //console.log(object[key][i]);
            }
        } else {
            sortedObj[key] = object[key];
        }
    }
    return sortedObj;
}
const sortedResult = sortObject(requestRebuilt);
console.log(sortedResult);

const requestOrdered = JSON.stringify(sortedResult);
console.log(requestOrdered);

var hash = CryptoJS.SHA256(requestOrdered).toString();
postman.setGlobalVariable("hash", hash);

示例输入:

{
    "username": "jdoe@mail.com",
    "sTime": "2016-03-04T13:53:37Z",
    "function": "begin",
    "functionParams": {
        "tip": "ABC123FFG",   
        "pad": 4 ,
        "passenger": [{
            "firstName": "John",
            "phone": 1234567890,
            "email": "jdoe@mail.com",
            "dateOfBirth": "1915-10-02T00:00:00Z",
            "bans": {
                "weight": 9,
                "count": 2
            }
        }
    ]},
    "salt": "00d878f5e203",
    "pep": "sdeODQ0T"
}

在 python 中,这是通过以下方式完成的:

ordered = json.dumps(
   {"username": user, "password": password, "time": time, "function": function, "functionParams": functionParams, "salt": salt}
    sort_keys=True, separators=(',', ':'))

下单结果:

{"function":"begin","functionParams":{"passenger":[{"bans":{"count":2,"weight":9},"dateOfBirth":"1915-10-02T00:00:00Z","email":"jdoe@mail.com","firstName":"John","phone":1234567890}],"pad":4,"tip":"ABC123FFG"},"pep":"sdeODQ0T","salt":"00d878f5e203","sTime":"2016-03-04T13:53:37Z","username":"jdoe@mail.com"}

印刷精美,便于阅读,但实际结果不应有空格或换行

    {
      "function": "begin",
      "functionParams": {
        "passenger": [
          {
            "bans": {
              "count": 2,
              "weight": 9
            },
            "dateOfBirth": "1915-10-02T00:00:00Z",
            "email": "jdoe@mail.com",
            "firstName": "John",
            "phone": 1234567890
          }
        ],
        "pad": 4,
        "tip": "ABC123FFG"
      },
      "pep": "sdeODQ0T",
      "salt": "00d878f5e203",
      "sTime": "2016-03-04T13:53:37Z",
      "username": "jdoe@mail.com"
    }

【问题讨论】:

  • 对象键在 JavaScript 中没有排序。因此,您不能使用JSON.stringify 来实现此目的。
  • 有什么解决办法吗?如果 javascript 不能保持顺序,你怎么能正确地散列一个对象?
  • 正如您所指出的,不可能在 JavaScript 中对对象键进行排序。你可以做的是创建一个[ ['key1', 'value1'], ['key2', 'value2'] ] 排序的数组来保留你感兴趣的顺序

标签: javascript python sorting recursion


【解决方案1】:

在 javascript 中“对象键没有排序”是一个常见的误解。 MDN states那个

尽管 ECMAScript 使对象的迭代顺序依赖于实现,但似乎所有主流浏览器都支持基于最早添加的属性的迭代顺序(至少对于不在原型上的属性)。

ES2015 makes this behaviour standard:

对于 O 的每个自己的属性键 P,它是一个字符串但不是整数索引,按属性创建顺序...

也就是说,您可以依赖对象属性始终按插入顺序迭代的事实(除非您使用的是delete,详情请参阅here)。

因此,要对某个对象中的键进行排序,只需创建一个新对象并按排序顺序向其中添加键:

function sortKeys(x) {
    if (typeof x !== 'object' || !x)
        return x;
    if (Array.isArray(x))
        return x.map(sortKeys);
    return Object.keys(x).sort().reduce((o, k) => ({...o, [k]: sortKeys(x[k])}), {});
}

////

obj = {
    "username": "jdoe@mail.com",
    "sTime": "2016-03-04T13:53:37Z",
    "function": "begin",
    "functionParams": {
        "tip": "ABC123FFG",
        "pad": 4,
        "passenger": [{
            "firstName": "John",
            "phone": 1234567890,
            "email": "jdoe@mail.com",
            "dateOfBirth": "1915-10-02T00:00:00Z",
            "bans": {
                "weight": 9,
                "count": 2
            }
        }
        ]
    },
    "salt": "00d878f5e203",
    "pep": "sdeODQ0T"
}


sorted = sortKeys(obj);
console.log(sorted);

【讨论】:

  • 不错!我只需要将 if(typeof x !== 'object') 替换为 if(typeof x !== 'object' || x === null) 即可防止它在空值上绊倒
猜你喜欢
  • 2018-04-20
  • 1970-01-01
  • 2021-10-25
  • 1970-01-01
  • 2016-07-01
  • 2012-02-12
  • 1970-01-01
  • 2023-04-04
  • 2019-11-23
相关资源
最近更新 更多