如何将使用全局变量的递归函数转换为纯函数?

时间:2018-11-07 03:24:58

标签: javascript recursion

我有一个程序,可以对提供给它的2个对象进行深度比较,并使用递归进行。我的问题是,由于我使用全局变量来保留信息,因此必须在每次对该函数进行任何后续调用之前都将其重置。除了使用全局变量之外,是否还有其他方法可以维护变量值,并且它不是那么麻烦?

Xaml

4 个答案:

答案 0 :(得分:2)

您根本不需要使用它:您可以通过递归来完成整个操作:

       time           col1     col2     col3
 2018-04-29 02:12:00    1       50        3
 2018-04-30 01:58:00    1       40        3
 2018-05-01 23:34:00    1       11        3
 2018-04-29 02:02:00    2       10        4
 2018-05-01 05:48:00    2       25        4

答案 1 :(得分:0)

我创建了一个实用程序,用于深入比较两个对象。它对两个对象使用递归调用,并返回true或false。

Github回购链接-https://github.com/maninder-singh/deep-compare

DOCKET

JS

<script src="deep-compare.js"></script>

答案 2 :(得分:0)

您可以使用我的各种JS库提供的经过测试的防弹对象相等方法来执行对象相等测试,如下所示

lodash库:

_.isEqual(obj1, obj2)


自定义测试方法

function deepCompare () {
  var i, l, leftChain, rightChain;

  function compare2Objects (x, y) {
    var p;

    // remember that NaN === NaN returns false
    // and isNaN(undefined) returns true
    if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
         return true;
    }

    // Compare primitives and functions.     
    // Check if both arguments link to the same object.
    // Especially useful on the step where we compare prototypes
    if (x === y) {
        return true;
    }

    // Works in case when functions are created in constructor.
    // Comparing dates is a common scenario. Another built-ins?
    // We can even handle functions passed across iframes
    if ((typeof x === 'function' && typeof y === 'function') ||
       (x instanceof Date && y instanceof Date) ||
       (x instanceof RegExp && y instanceof RegExp) ||
       (x instanceof String && y instanceof String) ||
       (x instanceof Number && y instanceof Number)) {
        return x.toString() === y.toString();
    }

    // At last checking prototypes as good as we can
    if (!(x instanceof Object && y instanceof Object)) {
        return false;
    }

    if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
        return false;
    }

    if (x.constructor !== y.constructor) {
        return false;
    }

    if (x.prototype !== y.prototype) {
        return false;
    }

    // Check for infinitive linking loops
    if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
         return false;
    }

    // Quick checking of one object being a subset of another.
    // todo: cache the structure of arguments[0] for performance
    for (p in y) {
        if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
            return false;
        }
        else if (typeof y[p] !== typeof x[p]) {
            return false;
        }
    }

    for (p in x) {
        if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
            return false;
        }
        else if (typeof y[p] !== typeof x[p]) {
            return false;
        }

        switch (typeof (x[p])) {
            case 'object':
            case 'function':

                leftChain.push(x);
                rightChain.push(y);

                if (!compare2Objects (x[p], y[p])) {
                    return false;
                }

                leftChain.pop();
                rightChain.pop();
                break;

            default:
                if (x[p] !== y[p]) {
                    return false;
                }
                break;
        }
    }

    return true;
  }

  if (arguments.length < 1) {
    return true; //Die silently? Don't know how to handle such case, please help...
    // throw "Need two or more arguments to compare";
  }

  for (i = 1, l = arguments.length; i < l; i++) {

      leftChain = []; //Todo: this can be cached
      rightChain = [];

      if (!compare2Objects(arguments[0], arguments[i])) {
          return false;
      }
  }

  return true;
}

参考:Object comparison in JavaScript

答案 3 :(得分:0)

function deepEqual(object1, object2) {
  //check if the given objects have the same datatype
  if (typeof(object1) === typeof(object2)) {
    //check if the given object is a primitive datatype and how to handle null values
    if ((typeof(object1) !== 'object') && (typeof(object2) !== 'object') ||
      object1 === null || object2 === null) {
      return object1 === object2;
    } else {
      //if they are both objects
      if (object1 !== null && object2 !== null) {
        let object1Keys = Object.keys(object1);
        let object2Keys = Object.keys(object2);

        //check if the arrays have the same length
        if (object1Keys.length === object2Keys.length) {
          let isEqual;
          for (let index = 0; index < object1Keys.length; index++) {
            //make sure both key:value pairs match
            if (object1Keys[index] === object2Keys[index]) {
              //check if the current value is another object
              if (typeof(object1[object1Keys[index]]) === 'object' &&
                typeof(object2[object2Keys[index]]) === 'object') {
                return deepEqual(object1[object1Keys[index]], object2[object2Keys[index]]);
              } else {

                isEqual = (object1[object1Keys[index]] === object2[object2Keys[index]]);
              }
            } else {

              return false; //return false if keys dont match
            }
          }
          return isEqual;

        } else {
          return false; //return false if 2 arrays dont have the same length
        }

      }
    }
  } else {
    return false; //return false if 2 object types dont match
  }
}

let obj1 = {
  a: 'somestring',
  b: 42,
  c: {
    1: 'one',
    2: {
      3: 'Three'
    }
  }
};

let obj2 = {
  a: 'somestring',
  b: 42,
  e: {
    1: 'one',
    2: {
      3: 'Three'
    }
  }
};
console.log("obj1 == obj2 : ");
console.log(deepEqual(obj1, obj2));


let obj3 = {
  a: 'somestring',
  b: 42,
  c: {
    1: 'one',
    2: {
      4: 'Three'
    }
  }
};

let obj4 = {
  a: 'somestring',
  b: 42,
  c: {
    1: 'one',
    2: {
      3: 'Three'
    }
  }
};
console.log("obj3 == obj4 : ");

console.log(deepEqual(obj3, obj4));
let obj = {
  name: {
    gender: "F"
  },
  age: 20
};

console.log(deepEqual(obj, {
  name: {
    gender: "F"
  },
  age: 20
}));
console.log('null == obj3');
console.log(deepEqual(null, obj3));
console.log('5 == obj3');
console.log(deepEqual(5, obj3));
console.log('null == null');
console.log(deepEqual(null, null));
console.log('10 == 5');
console.log(deepEqual(10, 5));
console.log(`10 == '10'`);
console.log(deepEqual(10, '10'));

老实说,我更喜欢@Andrew Ridgway的解决方案。它非常简单而优雅。

但是,我确实清理了我正在使用的函数,以避免使用全局变量。

这是解决同一问题的另一种方法,尽管有点复杂。

我愿意接受进一步的建议。谢谢!