我需要递归检查两个对象并且键需要排序,所以我创建了两个函数。
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)
执行示例 [ [ [ 'boo' ] ], 'foo' ]
真正的代码是做两个对象的差异,因为复杂我不写在这里。这是结构的简单示例。
最佳答案
误解
I define
buildObj
beforebuildObjKey
and callbuildObjKey
while its not defined yet... This is bad practice, but if I move definition ofbuildObj
afterbuildObjKey
I will callbuildObj
before It was defined...
这是不正确的。 buildObj
是一个函数,在您定义buildObjKey
之前不会调用它。 buildObj
包含对 buildObjKey
的引用这一事实并不意味着它会尝试立即调用它。为了具体说明这一点,让我们看下面的一个简化示例。
注意 isEven
和 isOdd
如何不产生输出直到其中一个函数被实际调用 -
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 中写了一个通用的对象差异函数。 .这展示了通用函数和可重用代码的优势。使用您问题中的 test1
和 test2
输入,我们可以计算出精确的差异,而无需对原始代码进行任何修改 -
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/