【问题标题】:Compare JS objects by their keys (with nesting)通过键比较 JS 对象(带有嵌套)
【发布时间】:2015-03-02 16:55:14
【问题描述】:

我有一个 JS 代码包来处理基本的国际化。

var EN = {
    messages: {
        newButton: {
            text: "New"
        },
        userSettings: {
            language: {
                selectYourLanguage: "Choose your preferred language",
                fr: "French",
                en: "English"
            }
        }
    }
};


var FR = {
    messages: {
        newButton: {
            text: "Nouveau"
        },
        userSettings: {
            language: {
                selectYourLanguage: "Choissez votre langage préféré:",
                fr: "Français",
                en: "Anglais"
            }
        }
    }
};

我想知道是否可以通过它们的“路径”来比较这两个对象。我希望能够确保没有不在第二个对象中的第一个对象的路径。

我想确保有人为一种语言添加翻译,永远不要忘记将它也添加到另一种语言,以快速失败。

我希望将来能够添加新的语言。

有什么优雅通用的方法来实现这一点吗?

我正在寻找类似的东西

haveSameKeys(objectList)

其中 objectList 包含对象(如 FR / EN / ...)。顺序应该无关紧要。该列表将保持相对较小的大小。

我更喜欢返回结果的纯解决方案,不涉及警报或抛出错误等副作用。

我并不真正关心运行时性能,因为它会在开发/集成中快速失败并且不会在生产中运行。

【问题讨论】:

  • 迭代和比较?
  • 您可能想要删除“关于库或自定义代码的任何想法来处理它?”因为要求库或代码是关闭问题的理由。
  • 你真的希望有人给你完整的解决方案,而你自己却没有做任何事情来解决它吗?至少我没有看到你尝试的任何证据。
  • 查看我的对象匹配器库:github.com/bvaughn/jasmine-object-matchers。做你正在寻找的东西,但在 Jasmine 插件的上下文中。你应该可以移植它。

标签: javascript


【解决方案1】:

一个简单的解决方案是使用与此类似的函数“展平”两个对象:

function flatObj(obj, key, res) {
  res = res || {};
    
  if(typeof obj != "object" || obj === null) {
    res[key] = obj;
    return res;
  }
  
  return Object.keys(obj).reduce(function(res, k) {
    return flatObj(obj[k], (key || "") + "." + k, res);
  }, res);
}
  



var EN = {
    messages: {
        newButton: {
            text: "New"
        },
        userSettings: {
            language: {
                selectYourLanguage: "Choose your preferred language",
                fr: "French",
                en: "English"
            }
        }
    }
};

flat = flatObj(EN)
document.write("<pre>"+JSON.stringify(flat,0,3))

然后计算Object.keys(flat(EN))Object.keys(flat(FR))之间的集合差。

【讨论】:

  • 这似乎是迄今为止最优雅和可重用的解决方案。谢谢
  • 我接受这个答案,因为它给了我最终解决方案的灵感:stackoverflow.com/a/28829861/82609
  • @SebastienLorber:谢谢,但您实际上应该接受自己的答案,因为它更完整。接受并不是说“谢谢”,而是向未来的读者表明哪个答案适用于 OP。
【解决方案2】:

jsFiddle Demo

所以你想知道结构是否与另一个对象完全相同?然后每个键必须出现在另一个对象中。

我希望能够确保没有不在第二个对象中的第一个对象的路径。

翻译:对象 b 中的所有路径都必须在对象 a 中。

function compare(a,b){
 //all paths in b must be in a
 for(var key in b){
  if(a[key] == undefined) return false;
  if(toString.call(b[key]) == "[object Array]" || toString.call(b[key]) == "[object Object]"){
   if( !compare(a[key],b[key]) ) return false;    
  }
 }
 return true;
}

此函数通过对象 b 递归并确保对象中的键存在于顶层和每个嵌套级别的 a 中。如果对象 b 包含在同一嵌套级别的对象 a 中不存在的键,它将返回 false。

为了将函数用于对象列表,您可以使用嵌套的 for 循环将它们相互比较

function haveSameKeys(objectList){
 for(var i = 0; i < objectList.length; i++)
 {
  for(var n = i+1; n < objectList.length; n++){
   if( !(compare(objectList[i],objectList[n]) && compare(objectList[n],objectList[i]) ) ) return false;
  }
 }
 return true;
}

【讨论】:

  • 如果 var FR = {},比较返回真,而我期待假
  • @SebastienLorber - 所以你希望它们是平等的,而不仅仅是所有的 b 都在 a 中。由于FR = {} 为空且不包含任何键,根据定义,FR 的所有键都在 a 中。
  • @SebastienLorber - 在你希望两者相等的情况下,它需要一个当且仅当它基本上是if( compare(a,b) &amp;&amp; compare(b,a) )。当FR = {}
  • 是的,可能有点混乱,我在我的问题中添加了一些信息
  • @SebastienLorber - 你的澄清有很大的不同。对于一组 10 个对象,确保每个对象都与其他对象相等,这将是 10!,这意味着如果没有优化的解决方案,您将看到 O(n!)。
【解决方案3】:

这是我最后使用的。

_.xor 函数调用需要下划线/lodash

function getPaths(obj, key, res) {
    res = res || {};
    if ( typeof obj != "object" || obj === null ) {
        res[key] = obj;
        return res;
    }
    return Object.keys(obj).reduce(function(res, k) {
        var prefix = key ? key + "." : ""
        return getPaths(obj[k], prefix + k, res);
    }, res);
}

function getPathsDifferences(objectArray) {
    var objectPaths = objectArray.map(function(o) {
        return Object.keys(getPaths(o));
    });
    return _.xor.apply(this,objectPaths);
}

var differences = getPathsDifferences([FR,EN]);
console.debug("differences",differences);
if ( differences.length > 0 ) {
    throw new Error("Localization bundles are not consistent on paths: \n" + differences.join("\n"));
}

【讨论】:

    【解决方案4】:

    使用lodash...

    function compareObjects(firstObject, secondObject) {
      var keys = _.keys(firstObject);
    
      for (var i = 0, length = keys.length; i < length; i++) {
        var key = keys[i];
        if (!secondObject.hasOwnProperty(key)) {
          // This is what you don't want
        } else if (firstObject[key] instanceof Object) {
          compareObjects(firstObject[key], secondObject[key]);
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-12
      • 1970-01-01
      • 2018-01-30
      • 1970-01-01
      • 2020-07-23
      • 1970-01-01
      相关资源
      最近更新 更多