javascript - 两个函数之间的递归调用

标签 javascript function recursion functional-programming

我需要递归检查两个对象并且键需要排序,所以我创建了两个函数。

buildObj - 从对象中获取所有 uniq 键,对它们进行排序并在每个键上调用 buildObjKey

buildObjKey - 如果其中一个值是对象调用 buildObj。其他返回是示例,实际代码更复杂。

所以问题:我在 buildObjKey 之前定义了 buildObj 并在尚未定义时调用 buildObjKey。这是不好的做法,但如果我在 buildObjKey 之后移动 buildObj 的定义,我将在它被定义之前调用 buildObj ......这是可能的在两个函数之间进行递归调用没有这个麻烦吗?

const _ = require('lodash')

const example1 = {
  key3: 'foo',
  key1: {
    key4: {
      key6: 'boo'
    },
  },
}

const example2 = {
  key3: 'too',
  key1: {
    key4: {
      key6: 'hoo'
    },
  },
}

const buildObj = (obj1, obj2) => {
 return  _.uniq([...Object.keys(obj1), ...Object.keys(obj2)])
 .sort()
 .map(key => buildObjKey(key, obj1, obj2))
}

const buildObjKey = (key, obj1, obj2) => {
  const val1 = obj1[key];
  const val2 = obj2[key];
  if(val1 && val2){
    if(_.isObject(val1) && _.isObject(val2)){
      return buildObj(val1, val2)
    }
    if(_.isObject(val1)){
      return buildObj(val1, val1)
    }
    if(_.isObject(val2)){
      return buildObj(val2, val2)
    }
    return val1
  }
  return val1 || val2
}

buildObj(example1, example2)

enter image description here

执行示例 [ [ [ 'boo' ] ], 'foo' ]

真正的代码是做两个对象的差异,因为复杂我不写在这里。这是结构的简单示例。

最佳答案

误解

I define buildObj before buildObjKey and call buildObjKey while its not defined yet... This is bad practice, but if I move definition of buildObj after buildObjKey I will call buildObj before It was defined...

这是不正确的。 buildObj 是一个函数,在您定义buildObjKey 之前不会调用它。 buildObj 包含对 buildObjKey 的引用这一事实并不意味着它会尝试立即调用它。为了具体说明这一点,让我们看下面的一个简化示例。

注意 isEvenisOdd 如何不产生输出直到其中一个函数被实际调用 -

function isEven (n)
{ console.log("isEven", n)
  if (n == 0)
    return true
  else
    return isOdd(n - 1)   // <- calls isOdd
}

function isOdd (n)
{ console.log("isOdd", n)
  if (n == 0)
    return false
  else
    return isEven(n - 1)  // <- calls isEven
}

console.log("first line of output")

console.log("result", isOdd(3))

first line of output
isOdd 3
isEven 2
isOdd 1
isEven 0
result true

可能且强大

This is possible to do recursive calls between two functions without this trouble?

这是一种非常强大的技术,称为 mutual recursion .相互递归是处理递归树(如程序中的深层嵌套对象)的绝佳方式。你有很好的直觉来处理它们。参见 this Q&A一个实际的例子和解释。


相关

巧合的是,我在 this Q&A 中写了一个通用的对象差异函数。 .这展示了通用函数和可重用代码的优势。使用您问题中的 test1test2 输入,我们可以计算出精确的差异,而无需对原始代码进行任何修改 -

const test1 = {
  "common": {
    "setting1": "Value 1",
    "setting2": 200,
    "setting3": true,
    "setting6": {
      "key": "value",
      "doge": {
        "wow": ""
      }
    }
  },
  "group1": {
    "baz": "bas",
    "foo": "bar",
    "nest": {
      "key": "value"
    }
  },
  "group2": {
    "abc": 12345,
    "deep": {
      "id": 45
    }
  }
}
const test2 = {
  "common": {
    "follow": false,
    "setting1": "Value 1",
    "setting3": null,
    "setting4": "blah blah",
    "setting5": {
      "key5": "value5"
    },
    "setting6": {
      "key": "value",
      "ops": "vops",
      "doge": {
        "wow": "so much"
      }
    }
  },
  "group1": {
    "foo": "bar",
    "baz": "bars",
    "nest": "str"
  },
  "group3": {
    "fee": 100500,
    "deep": {
      "id": {
        "number": 45
      }
    }
  }
}
console.log(diff(test1, test2))

展开下面的代码片段以在您自己的浏览器中验证 diff 的结果 -

const isObject = x =>
  Object(x) === x

const isArray =
  Array.isArray

const mut = (o, [ k, v ]) =>
  (o[k] = v, o)

const diff1 = (left = {}, right = {}, rel = "left") =>
  Object
    .entries(left)
    .map
      ( ([ k, v ]) =>
          isObject(v) && isObject(right[k])
            ? [ k, diff1(v, right[k], rel) ]
        : right[k] !== v
            ? [ k, { [rel]: v } ]
        : [ k, {} ]
      )
    .filter
      ( ([ _, v ]) =>
          Object.keys(v).length !== 0
      )
    .reduce
      ( mut
      , isArray(left) && isArray(right) ? [] : {}
      )

const merge = (left = {}, right = {}) =>
  Object
    .entries(right)
    .map
      ( ([ k, v ]) =>
          isObject(v) && isObject(left [k])
            ? [ k, merge(left [k], v) ]
            : [ k, v ]
      )
    .reduce(mut, left)


const diff = (x = {}, y = {}, rx = "left", ry = "right") =>
  merge
    ( diff1(x, y, rx)
    , diff1(y, x, ry)
    )

const test1 = {
  "common": {
    "setting1": "Value 1",
    "setting2": 200,
    "setting3": true,
    "setting6": {
      "key": "value",
      "doge": {
        "wow": ""
      }
    }
  },
  "group1": {
    "baz": "bas",
    "foo": "bar",
    "nest": {
      "key": "value"
    }
  },
  "group2": {
    "abc": 12345,
    "deep": {
      "id": 45
    }
  }
}

const test2 = {
  "common": {
    "follow": false,
    "setting1": "Value 1",
    "setting3": null,
    "setting4": "blah blah",
    "setting5": {
      "key5": "value5"
    },
    "setting6": {
      "key": "value",
      "ops": "vops",
      "doge": {
        "wow": "so much"
      }
    }
  },
  "group1": {
    "foo": "bar",
    "baz": "bars",
    "nest": "str"
  },
  "group3": {
    "fee": 100500,
    "deep": {
      "id": {
        "number": 45
      }
    }
  }
}

console.log(diff(test1, test2))

{
  "common": {
    "setting2": {
      "left": 200
    },
    "setting3": {
      "left": true,
      "right": null
    },
    "setting6": {
      "doge": {
        "wow": {
          "left": "",
          "right": "so much"
        }
      },
      "ops": {
        "right": "vops"
      }
    },
    "follow": {
      "right": false
    },
    "setting4": {
      "right": "blah blah"
    },
    "setting5": {
      "right": {
        "key5": "value5"
      }
    }
  },
  "group1": {
    "baz": {
      "left": "bas",
      "right": "bars"
    },
    "nest": {
      "left": {
        "key": "value"
      },
      "right": "str"
    }
  },
  "group2": {
    "left": {
      "abc": 12345,
      "deep": {
        "id": 45
      }
    }
  },
  "group3": {
    "right": {
      "fee": 100500,
      "deep": {
        "id": {
          "number": 45
        }
      }
    }
  }
}

关于javascript - 两个函数之间的递归调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65651581/

相关文章:

php - PHP 应用程序中的函数是否可能过多?

C++ 标记 3D 对象数组中的连续部分

javascript - 调用函数定义变量

javascript - 使用 JavaScript,将换行符插入 HTML textContent 属性(特定于 IE)

javascript - &&/|| JavaScript 中的运算符奇怪性

javascript - 如果鼠标指针太近则停止旋转图像

list - 如何将 Scheme 中的函数应用于另一个函数返回的参数列表?

javascript - 如何使用 jQuery 调用特殊函数?

c代码使用递归打印数组的反向

java - 使用递归计算后缀表达式