通过键来比较JS对象(使用嵌套)

时间:2015-03-02 16:55:14

标签: javascript

我有一个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"
            }
        }
    }
};

我想知道是否可以通过"路径"比较2个对象。我希望能够确保没有第一个对象的路径也不在第二个对象中。

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

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

有什么想法以优雅和通用的方式来实现这一目标吗?

我正在寻找类似的东西

haveSameKeys(objectList)

其中objectList包含对象(如FR / EN / ...)。订单无关紧要。该列表将保持相对较小的规模。

我倾向于选择返回结果的纯解决方案,而不涉及警告或抛出错误等副作用。

我并不十分关心运行时性能,因为它在开发/集成方面快速失败并且无法在生产中运行。

4 个答案:

答案 0 :(得分:1)

<强> 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递归,并确保对象中的键存在于顶层和每个嵌套层中。如果对象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;
}

答案 1 :(得分:1)

一个简单的解决方案就是“平坦化”#34;两个对象使用类似于此的函数:

&#13;
&#13;
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))
&#13;
&#13;
&#13;

然后计算Object.keys(flat(EN))Object.keys(flat(FR))之间的设置差异。

答案 2 :(得分:1)

这是我最终使用的内容。

_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"));
}

答案 3 :(得分:0)

使用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]);
    }
  }
}