如何从JavaScript对象生成校验和?

如何从JavaScript对象生成校验和?,javascript,json,checksum,adler32,Javascript,Json,Checksum,Adler32,我需要对JavaScript对象进行校验和。 不幸的是,由于JavaScript的对象顺序,似乎没有一种简单的方法来实现这一点。例如,以以下对象为例: var obj1 = {type:"cake",quantity:0} , obj2 = {quantity:0,type:"cake"}; 我认为这些对象在数据上是相等的,并且希望它们的校验和是相同的。我真的不在乎对象的顺序,只要它们中的数据相同。 唉,JSON.stringify两者实际上并不相等;由于对对象进行校验和的唯一方法是通过其

我需要对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 OS浏览器中,你可以在这里自己检查:),当然它使两个对象字符串表示相等

然而,我只是想知道我是否错过了一些东西,并且有一个内置的方法一直以来都是这样的,它没有a)将JavaScript GC驱动到病态情况,或者b)进行过多的字符串连接。
我不想这样做。

您可以使用
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);
}
//创建交替属性名称、属性值的数组
//具有按排序的属性
//那就是那个数组
函数stringifyPropsInOrder(obj){
var keys=Object.keys(obj.sort();
var输出=[],prop;
对于(变量i=0;i
如果您想要更快的性能,就不必进行字符串化(这只是为了保存代码)。您只需返回展平的
输出
数组,并直接比较数组



如果可以将嵌入的对象作为属性值,那么还需要做更多的工作,将这些对象循环扩展到相同的扁平属性/值数组中。

您还可以制作一个函数来比较您的对象:

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;
}
函数比较对象(a、b){
var-akeys=Object.keys(a);
var bkeys=对象键(b);
var len=akeys.长度;
如果(len!=bkeys.length)返回false;
对于(变量i=0;i

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

3年后…

我遇到这个问题是因为我想散列我的JSON对象,为我的HTTP响应创建
Etag
s。因此,我最终为Node编写了自己的解决方案,可以归结为一个简单的序列化程序:

/**
*字符串化JSON对象(不是任何randon JS对象)。
*
*应该注意的是,JS对象可以有
*不受支持的特定类型(如功能)
*通过JSON。
*
*@param{Object}obj JSON对象
*@返回{String}字符串化的JSON对象。
*/
函数序列化(obj){
if(数组isArray(obj)){
返回JSON.stringify(obj.map(i=>serialize(i)))
}else if(对象的类型=='object'&&obj!==null){
返回Object.keys(obj)
.sort()
.map(k=>`${k}:${serialize(obj[k])}`)
.join(“|”)
}
返回obj
}
然后,您可以使用常用算法(例如
SHA256
)或使用
jsum
包中的
digest
方便方法获取结果并对其进行散列



请注意许可证

您不应该将
用于。。。在
循环中,在JavaScript中迭代数组。使用带有索引变量的普通
for
循环,或者使用
.forEach()
。对象中的所有属性值都是简单值,或者可以是对象或数组(例如嵌套结构)?@jfriend00我本来打算在里面放一个对象,但这不是必须的,这只意味着你必须检查每个值的类型,并决定是否需要扩展它。它只是添加了更多的代码,但肯定是可行的
的顺序完全相同,不保证是任何特定的。不,因为它只使用
akeys
。您假设两个对象上的给定属性都位于
akeys
bKeys
中完全相同的数组槽中。你能给我看一份说明书,上面说这是保证真实的吗?实际上,从
Object.keys()
返回的键可以是任意顺序。您可以对密钥数组进行排序以删除此问题