JavaScript:递归深度比较:对象和属性 [英] JavaScript: Deep comparison recursively: Objects and properties

查看:102
本文介绍了JavaScript:递归深度比较:对象和属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天我读完了Ch。 4在Eloquent JS中,我很难理解如何在对象及其属性之间进行深度比较,特别是通过使用递归调用。我知道下面我的解决方案很天真,有点笨重,但我正试图把我所有的新东西都包围起来,我还在学习!只需不到一个月的编程:)我将不胜感激任何提示和帮助,你可能有改进代码,如果你可以帮助我更好地理解需要发生的递归。提前谢谢你!

Today I finished reading Ch. 4 in Eloquent JS and I'm struggling to understand how to perform a deep comparison between objects and their properties, particularly through the use of a recursive call. I know my solution below is quite naive and a bit bulky, but I'm trying to wrap my head around all these new things I'm still learning! Just less than a month in on programming :) I would appreciate any tips and help you might have in improving the code and also if you could help me better understand the recursion that needs to occur. Thank you in advance!


  • 问题(Eloquent JS第2版,第4章,练习4):

    • Question (Eloquent JS 2nd Ed, Chapter 4, Exercise 4):


      编写一个函数deepEqual,它接受两个值,只有当它们是相同的值或者是具有相同
      的对象时才返回true
      与对deepEqual的递归
      调用相比,其值也相等的属性。




    • var obj = {here: {is: "an"}, object: 2};
      var obj1 = {here: {is: "an"}, object: 2};
      console.log(deepEqual(obj,obj1));
      

      我的代码:

        function objectTester(x) {
            if (typeof x === 'object' && x !== null)
              return true;
          }
      
          function deepEqual(valOne, valTwo) {
            if (valOne === valTwo) return true;
      
            var comp1 = objectTester(valOne);
            var comp2 = objectTester(valTwo);
      
            if (comp1 === comp2) {
              var count1;
              var count2;
              for (var prop in valOne) {
                  count1++
                  return count1;
              }
              for (var prop in valTwo) {
                  count2++
                  return count2;
              }
              if (count1 === count2) {
      
              // This is where I'm getting stuck, not sure how I can recurisvely compare
              // two arguments that are to be compared. 
            }
          }
      


      推荐答案

      可能最简单的方法就是发布一个有大量注释的函数。递归部分靠近底部,在传递给每个的函数中:

      Probably easiest to just post a function that does the job with plenty of comments. The recursive part is near the bottom, in the function passed to every:

      // Helper to return a value's internal object [[Class]]
      // That this returns [object Type] even for primitives
      function getClass(obj) {
        return Object.prototype.toString.call(obj);
      }
      
      /*
      ** @param a, b        - values (Object, RegExp, Date, etc.)
      ** @returns {boolean} - true if a and b are the object or same primitive value or
      **                      have the same properties with the same values
      */
      function objectTester(a, b) {
      
        // If a and b reference the same value, return true
        if (a === b) return true;
      
        // If a and b aren't the same type, return false
        if (typeof a != typeof b) return false;
      
        // Already know types are the same, so if type is number
        // and both NaN, return true
        if (typeof a == 'number' && isNaN(a) && isNaN(b)) return true;
      
        // Get internal [[Class]]
        var aClass = getClass(a);
        var bClass = getClass(b)
      
        // Return false if not same class
        if (aClass != bClass) return false;
      
        // If they're Boolean, String or Number objects, check values
        if (aClass == '[object Boolean]' || aClass == '[object String]' || aClass == '[object Number]') {
          return a.valueOf() == b.valueOf();
        }
      
        // If they're RegExps, Dates or Error objects, check stringified values
        if (aClass == '[object RegExp]' || aClass == '[object Date]' || aClass == '[object Error]') {
          return a.toString() == b.toString();
        }
      
        // Otherwise they're Objects, Functions or Arrays or some kind of host object
        if (typeof a == 'object' || typeof a == 'function') {
      
          // For functions, check stringigied values are the same
          // Almost certainly false if a and b aren't trivial
          // and are different functions
          if (aClass == '[object Function]' && a.toString() != b.toString()) return false;
      
          var aKeys = Object.keys(a);
          var bKeys = Object.keys(b);
      
          // If they don't have the same number of keys, return false
          if (aKeys.length != bKeys.length) return false;
      
          // Check they have the same keys
          if (!aKeys.every(function(key){return b.hasOwnProperty(key)})) return false;
      
          // Check key values - uses ES5 Object.keys
          return aKeys.every(function(key){
            return objectTester(a[key], b[key])
          });
        }
        return false;
      }
      

      对Date,RegExp,Error等的测试应该返回false值/字符串不一样,然后通过属性检查,但只有当你认为有人可能将属性附加到Number对象时才这样做(使用Number对象极为罕见,更不用说为它们添加属性了,但我猜它可能会发生。)

      The tests on Date, RegExp, Error, etc. should probably return false if the values/strings aren't the same then fall through to the property checks, but do that only if you think someone might attach properties to Number objects (it's extremely rare to use Number objects, much less add properties to them, but I guess it might happen).

      这是:

      /*
      ** @param a, b        - values (Object, RegExp, Date, etc.)
      ** @returns {boolean} - true if a and b are the object or same primitive value or
      **                      have the same properties with the same values
      */
      function objectTester(a, b) {
      
        // If a and b reference the same value, return true
        if (a === b) return true;
      
        // If a and b aren't the same type, return false
        if (typeof a != typeof b) return false;
      
        // Already know types are the same, so if type is number
        // and both NaN, return true
        if (typeof a == 'number' && isNaN(a) && isNaN(b)) return true;
      
        // Get internal [[Class]]
        var aClass = getClass(a);
        var bClass = getClass(b)
      
        // Return false if not same class
        if (aClass != bClass) return false;
      
        // If they're Boolean, String or Number objects, check values
        if (aClass == '[object Boolean]' || aClass == '[object String]' || aClass == '[object Number]') {
          if (a.valueOf() != b.valueOf()) return false;
        }
      
        // If they're RegExps, Dates or Error objects, check stringified values
        if (aClass == '[object RegExp]' || aClass == '[object Date]' || aClass == '[object Error]') {
          if (a.toString() != b.toString()) return false;
        }
      
        // For functions, check stringigied values are the same
        // Almost impossible to be equal if a and b aren't trivial
        // and are different functions
        if (aClass == '[object Function]' && a.toString() != b.toString()) return false;
      
        // For all objects, (including Objects, Functions, Arrays and host objects),
        // check the properties
        var aKeys = Object.keys(a);
        var bKeys = Object.keys(b);
      
        // If they don't have the same number of keys, return false
        if (aKeys.length != bKeys.length) return false;
      
        // Check they have the same keys
        if (!aKeys.every(function(key){return b.hasOwnProperty(key)})) return false;
      
        // Check key values - uses ES5 Object.keys
        return aKeys.every(function(key){
          return objectTester(a[key], b[key])
        });
        return false;
      }
      

      这篇关于JavaScript:递归深度比较:对象和属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆