简体   繁体   English

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

[英]How to convert a recursive function using a global variable in to a pure function?

I have a program that does a deep compare on 2 objects provided to it and uses recursion to do so. 我有一个程序,可以对提供给它的2个对象进行深度比较,并使用递归来做到这一点。 My problem is that since I am using a global variable to retain information, I have to reset it every time prior to making any subsequent calls to the function. 我的问题是,由于我使用全局变量来保留信息,因此必须在每次对该函数进行任何后续调用之前都将其重置。 Is there someway I can maintain the variable value other than using a global variable and have it be not so cumbersome? 除了使用全局变量之外,是否还有其他方法可以维护变量值并且它不那么麻烦?

 let isEqual = true; function deepEqual(object1, object2) { if (!((typeof(object1) == 'object' && typeof(object2) == 'object') || (object1 && object2))) { return isEqual = object1 === object2; } else if (typeof(object1) == 'object' && typeof(object2) == 'object') { if ((object1 && object2)) { let object1Keys = Object.keys(object1); let object2Keys = Object.keys(object2); if (object1Keys.length == object2Keys.length) { for (let index = 0; index < object1Keys.length; index++) { if (isEqual) { if (!(typeof(object1[object1Keys[index]]) == 'object' && typeof(object2[object2Keys[index]]) == 'object')) { isEqual = (object1[object1Keys[index]] === object2[object2Keys[index]]) && (object1Keys[index] === object2Keys[index]); } else { deepEqual(object1[object1Keys[index]], object2[object2Keys[index]]); } } else { return isEqual = false; } } } } } return isEqual; } let obj1 = { a: 'somestring', b: 42, c: { 1: 'one', 2: { 4: 'Three' } } }; let obj2 = { a: 'somestring', b: 42, c: { 1: 'one', 2: { 3: 'Three' } } }; console.log("obj1 == obj2 : "); console.log(deepEqual(obj1, obj2)); let obj3 = { a: 'somestring', b: 42, c: { 1: 'one', 2: { 3: 'Three' } } }; let obj4 = { a: 'somestring', b: 42, c: { 1: 'one', 2: { 3: 'Three' } } }; console.log("obj3 == obj4 : "); isEqual = true; console.log(deepEqual(obj3, obj4)); let obj = {name: {gender: "F"}, age: 20}; isEqual = true; console.log(deepEqual(obj, {name: {gender: "F"}, age: 20})); 

You don't need to use it at all: you can do the whole thing via recursion: 您根本不需要使用它:您可以通过递归来完成整个操作:

function deepEqual(o1, o2){
  if (typeof o1 != typeof o2)
    return false;

  if (typeof o1 != 'object' || o1 === null || o2 === null)
    return o1 === o2;

  for (var k in o1){
   if (!deepEqual(o1[k], o2[k]))
    return false;
  }
  for (var k in o2){
    if (!(k in o1))
      return false;
  }
  return true;
}

I have created an utility just to deep compare two object. 我创建了一个实用程序,用于深入比较两个对象。 It uses the recursive call with two object and return true or false. 它对两个对象使用递归调用,并返回true或false。

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

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

JS JS

    1. dc(null,null);
    2. dc("a","a");
    3. dc("a","ab");
    4. dc("a",undefined);
    5. dc(undefined,undefined);
    6. dc({},[]);
    7. dc({a:1},{});
    8. dc({a:1},{a:1});
    9. dc(true,true);
    10. dc(true,false);

You can use tested, bullet proof Object equality methods provided my various JS library to perform Object equality testing as illustrated below 您可以使用我的各种JS库提供的经过测试的,防弹的对象相等方法来执行对象相等测试,如下所示

lodash Library: lodash库:

_.isEqual(obj1, obj2)

Or 要么
Custom Tested Method 定制测试方法

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;
}

Reference: Object comparison in JavaScript 参考: JavaScript中的对象比较

 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')); 

In all honesty, I prefer @Andrew Ridgway's solution. 老实说,我更喜欢@Andrew Ridgway的解决方案。 Its very simple and elegant. 它非常简单而优雅。

However, I did clean-up the function I was using to avoid using global variables. 但是,我确实清理了我正在使用的函数,以避免使用全局变量。

This is another solution to same problem, though a bit complex. 这是解决相同问题的另一种方法,尽管有点复杂。

I am open to further suggestions. 我愿意接受进一步的建议。 Thanks! 谢谢!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM