【问题标题】:JavaScript: Deep check objects have same keysJavaScript:深度检查对象具有相同的键
【发布时间】:2017-06-07 17:18:49
【问题描述】:

问题类似于:How can I check that two objects have the same set of property names?,但只有一个区别

我要检查:

var objOne = {"a":"one","b":"two","c":{"f":"three_one"}};
var objTwo = {"a":"four","b":"five","c":{"f":"six_one"}};

在所有级别都有相同的

例如deepCheckObjKeys(objOne, objTwo) 将返回true 其中deepCheckObjKeys(objOne, objThree) 返回false,如果:

var objThree = {"a":"four","b":"five","c":{"g":"six_one"}};

因为objThree.a.c.fobjThree 中是undefined

这样的函数:

'使用严格';

function objectsHaveSameKeys() {
   for (var _len = arguments.length, objects = Array(_len), _key = 0; _key < _len; _key++) {
      objects[_key] = arguments[_key];
   }

   var allKeys = objects.reduce(function (keys, object) {
      return keys.concat(Object.keys(object));
   }, []);
   var union = new Set(allKeys);
   return objects.every(function (object) {
      return union.size === Object.keys(object).length;
   });
}

只检查第一级。

PS:objectsHaveSameKeys() ES6 等效:

function objectsHaveSameKeys(...objects):boolean {
   const allKeys = objects.reduce((keys, object) => keys.concat(Object.keys(object)), []);
   const union = new Set(allKeys);
   return objects.every(object => union.size === Object.keys(object).length);
}

【问题讨论】:

    标签: javascript key javascript-objects


    【解决方案1】:

    我猜您正在寻找 [此处] 提供的函数的深度检查版本 :)(How can I check that two objects have the same set of property names?)。

    以下是我的尝试。请注意:

    • 解决方案不检查 null 且不防弹
    • 我没有对它进行性能测试。也许 OP 或其他任何人都可以这样做并为社区分享。
    • 我不是 JS 专家 :)。
    function objectsHaveSameKeys(...objects) {
      const allKeys = objects.reduce((keys, object) => keys.concat(Object.keys(object)), [])
      const union = new Set(allKeys)
      if (union.size === 0) return true
      if (!objects.every((object) => union.size === Object.keys(object).length)) return false
    
      for (let key of union.keys()) {
        let res = objects.map((o) => (typeof o[key] === 'object' ? o[key] : {}))
        if (!objectsHaveSameKeys(...res)) return false
      }
      return true
    }
    

    【讨论】:

      【解决方案2】:

      我会递归检查一个属性的值是否是一个对象。

      这里有一个有趣的皱纹;实际上,有(至少)两个:

      • 如果“对象”之一是null 而另一个没有属性怎么办? truefalse?
      • 如果其中一个对象有{a: null} 而另一个有{a: 17} 怎么办? truefalse?
      • 如果其中一个对象具有{a: null} 而另一个对象具有{a: {}},该怎么办? truefalse?

      出于本示例的目的,我将null 视为没有属性的对象,但它非常在很大程度上取决于您的用例。我至少可以想到另外两种方法(null 除了null 之外不匹配任何东西,或者null 除了非对象之外不匹配任何东西,即使对象没有自己的属性)和可能还有其他人。

      见 cmets:

      const deepSameKeys = (o1, o2) => {
          // Both nulls = yes
          if (o1 === null && o2 === null) {
              return true;
          }
          // Get the keys of each object
          const o1keys = o1 === null ? [] : Object.keys(o1);
          const o2keys = o2 === null ? [] : Object.keys(o2);
          if (o1keys.length !== o2keys.length) {
              // Different number of own properties = not the same
              return false;
          }
          
          // At this point, one of two things is true:
          // A) `o1` and `o2` are both `!null`, or
          // B) One of them is `null` and the other has own "own" properties
          // The logic below relies on the fact we only try to use `o1` or
          // `o2` if there's at least one entry in `o1keys`, which we won't
          // given the guarantee above.
      
          // Handy utility function
          const hasOwn = Object.prototype.hasOwnProperty;
      
          // Check that the keys match and recurse into nested objects as necessary
          return o1keys.every(key => {
              if (!hasOwn.call(o2, key)) {
                  // Different keys
                  return false;
              }
              // Get the values and their types
              const v1 = o1[key];
              const v2 = o2[key];
              const t1 = typeof v1;
              const t2 = typeof v2;
              if (t1 === "object") {
                  if (t2 === "object" && !deepSameKeys(v1, v2)) {
                      return false;
                  }
              }
              if (t2 === "object") {
                  if (t1 === "object" && !deepSameKeys(v1, v2)) {
                      return false;
                  }
              }
              return true;
          });
      };
      
      // Checking your example
      const objOne   = {"a": "one",  "b": "two",  "c": {"f": "three_one"}};
      const objTwo   = {"a": "four", "b": "five", "c": {"f": "six_one"}};
      const objThree = {"a": "four", "b": "five", "c": {"g": "six_one"}};
      
      console.log("objOne vs. objTwo:         ", deepSameKeys(objOne, objTwo));        // true
      console.log("objTwo vs. objThree:       ", deepSameKeys(objTwo, objThree));      // false
      
      // `null` checks
      console.log("{a: null} vs. {a: 17}      ", deepSameKeys({a: null}, {a: 17}));    // true
      console.log("{a: null} vs. {a: {}}      ", deepSameKeys({a: null}, {a: {}}));    // true -- depending on your use case, you may want this to be false
      console.log("{a: null} vs. {a: {x:1}}   ", deepSameKeys({a: null}, {a: {x:1}})); // false
      
      // Differing value type check
      console.log("{a: 1} vs. {a: '1'}}       ", deepSameKeys({a: 1}, {a: '1'}));      // true

      【讨论】:

      • 不错。请问您为什么将内部变量声明为 const 而不是 var ?
      • @ThirueswaranRajagopalan:嗯,我和其他许多人。但是,是的,这几乎是一种风格,虽然它可能有助于编译器知道该变量不会改变而无需进行必要的静态分析来证明它......跨度>
      • 现在我自己实现了这个,我意识到数组也需要特殊处理。我认为在大多数情况下,当您检查对象的形状时,您会希望将 { foo: [1, 2] }{ foo: [] } 视为具有相同的键,但上面的代码将返回 false,因为数组有不同的键(这是真的,但并不真正相关)。
      • @jdunning - 完全取决于您的用例,但有时可以。
      • deepSameKeys({ a: null }, { a: 17 })deepSameKeys({ a: '1' }, { a: 1 }) 都返回 false
      【解决方案3】:

      您可以创建将返回所有键并检查它们是否与every() 相等的递归函数。

      var objOne = {"a":"one","b":"two","c":{"f":"three_one"}};
      var objTwo = {"a":"four","b":"five","c":{"f":"six_one"}};
      
      function checkKeys(obj1, obj2) {
      
        function inner(obj) {
          var result = []
      
          function rec(obj, c) {
            Object.keys(obj).forEach(function(e) {
              if (typeof obj[e] == 'object') rec(obj[e], c + e)
              result.push(c + e)
            })
          }
          rec(obj, '')
          return result
        }
      
        var keys1 = inner(obj1), keys2 = inner(obj2)
        return keys1.every(e => keys2.includes(e) && keys1.length == keys2.length)
      }
      
      console.log(checkKeys(objOne, objTwo))

      【讨论】:

      • {a: true, bc:true, b:true}{a: true, b:{c: true}} 错误地返回 true
      猜你喜欢
      • 2016-01-31
      • 2021-12-10
      • 2020-08-23
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 2021-11-06
      • 1970-01-01
      相关资源
      最近更新 更多