【问题标题】:How do I make a checksum from a JavaScript Object?如何从 JavaScript 对象生成校验和?
【发布时间】:2014-09-15 00:44:43
【问题描述】:

我需要从 JavaScript 对象生成校验和。
不幸的是,由于 JavaScript 的对象排序,似乎没有一种简单的方法可以实现这一点。例如,拿这些对象:

var obj1 = {type:"cake",quantity:0}
  , obj2 = {quantity:0,type:"cake"};

我认为这些对象的数据相同,并且希望它们的校验和相同。我真的不在乎对象的顺序,只要它们中的数据相同即可。
唉,两者的JSON.stringify其实是不相等的;因为对对象进行校验和的唯一方法是通过它的字符串表示,并且JSON.stringify-ed 表示不相等,所以我的校验和将不相等!
我想出的一种解决方案是根据预定义的模式重新创建对象,如下所示:

var schema = ["type","quantity"];
function sortify(obj,schema){
  var n={};
  for(i in schema)
    n[schema[i]]=obj[schema[i]];
  return n
}

运行JSON.stringify(sortify(obj1,schema))==JSON.stringify(sortify(obj2,schema)) 将返回true...但代价是创建一个新对象并在数据周围混洗。

我的另一个解决方案是将JSON.stringify 方法替换为从预定义模式中选择键并将它们的值字符串化,然后将它们连接在一起的方法。 函数内容如下:

function smarterStringify(obj,schema){
  var s="";
  for(i in schema)
    s+=JSON.stringify(obj[schema[i]]);
  return s
}

忽略这个方法没有返回正确的 JSON 的事实(作为我正在尝试做的一个例子,它已经足够接近了),它在速度上比第一个方法有了很大的改进(至少在我的 Chrome 操作系统中)浏览器,您可以在这里自己检查:http://jsperf.com/sort-then-json-stringify-vs-smarter-stringify),当然它使两个 Object String 表示相等!

但是,我只是想知道我是否遗漏了一些东西,并且一直以来都有一个内置方法可以解决这样的问题串联。 我宁愿不这样做。

【问题讨论】:

  • 您不应该使用 for ... in 循环来遍历 JavaScript 中的数组。使用带有索引变量的普通 for 循环或使用 .forEach()
  • 您的对象中的所有属性值都是简单值还是其中一些可以是对象或数组(例如嵌套结构)?
  • @jfriend00 我本来打算在里面放另一个对象,但这不是必需品
  • 这只是意味着您必须检查每个值的类型并决定是否还需要扩展它。它只是添加了更多代码,但肯定是可行的。

标签: javascript json checksum adler32


【解决方案1】:

您可以使用Object.keys() 将键收集到一个数组中,对该数组进行排序,然后以已知的可预测顺序对键/值进行校验和。我不知道有什么方法可以同时使用 JSON.stringify() 和所有排序的键,所以你必须自己做校验和。

我不知道有任何类似的内置方法。不保证对象键具有任何特定顺序,因此依赖它是不安全的。


如果您没有嵌套对象或数组作为属性值,那么您可以执行以下操作:

// creates an array of alternating property name, property value
// with properties in sorted order
// then stringify's that array
function stringifyPropsInOrder(obj) {
    var keys = Object.keys(obj).sort();
    var output = [], prop;
    for (var i = 0; i < keys.length; i++) {
        prop = keys[i];
        output.push(prop);
        output.push(obj[prop]);
    }
    return JSON.stringify(output);
}

function compareObjects(a, b) {
    return stringifyPropsInOrder(a) === stringifyPropsInOrder(b);
}

如果您想要更快的性能,则不必进行字符串化(这里只是为了节省代码)。您可以只返回扁平化的 output 数组并直接比较数组。


如果您可以将嵌入的对象作为属性值,那么还需要做一些工作才能将它们递归地扩展为相同的扁平属性/值数组。

【讨论】:

    【解决方案2】:

    您还可以创建一个函数来比较您的对象:

    function compareObjects(a, b) {
      var akeys = Object.keys(a);
      var bkeys = Object.keys(b);
      var len = akeys.length;
      if (len != bkeys.length) return false;
      for (var i = 0; i < len; i++) {
        if (a[akeys[i]] !== b[akeys[i]]) return false;
      }
      return true;
    }
    

    这假设它们是传入的对象,并且它们是简单的平面对象。可以添加逻辑来检查这些假设并递归检查子对象是否相等。

    【讨论】:

    • 不,因为它只使用akeys
    • 您假设两个对象上的给定属性最终位于aKeysbKeys 中完全相同的数组槽中。你能给我看一个说明保证是真的规范吗?事实上,从Object.keys() 返回的键可以是任意顺序的。您可以对键数组进行排序以消除此问题。
    • 还有一个问题。这两个对象将显示为相等的{hello: true}{hello: 1},因为您使用的是!= 而不是!==
    • 老兄……说真的。退后一步。你错过了一些东西。此处的顺序无关紧要,并且不涉及现代浏览器技巧。在这里,这种排序是完全没有必要的。签入密钥的顺序无关紧要,只要它们都被检查过。从 A 中的键逐个键,确保该键的值在 A 和 B 上是相同的。够了。
    • 没有。不,不,我一点也不假设。我不在乎它们以什么顺序返回。你完全误解了这里发生的事情,应该停止。
    【解决方案3】:

    3 年后...

    我遇到了这个问题,因为我想对我的 JSON 对象进行哈希处理,以便为我的 HTTP 响应创建 Etags。所以我最终为 Node 编写了自己的解决方案,jsum,归结为一个简单的序列化程序:

    /**
     * Stringifies a JSON object (not any randon JS object).
     *
     * It should be noted that JS objects can have members of
     * specific type (e.g. function), that are not supported
     * by JSON.
     *
     * @param {Object} obj JSON object
     * @returns {String} stringified JSON object.
     */
    function serialize (obj) {
      if (Array.isArray(obj)) {
        return JSON.stringify(obj.map(i => serialize(i)))
      } else if (typeof obj === 'object' && obj !== null) {
        return Object.keys(obj)
          .sort()
          .map(k => `${k}:${serialize(obj[k])}`)
          .join('|')
      }
    
      return obj
    }
    

    然后您可以使用常用算法(例如SHA256)或使用jsum 包中的digest 的便捷方法获取结果并对其进行哈希处理。


    请注意许可证here

    【讨论】:

    猜你喜欢
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多