我无法理解以下缩减功能:
function findDeep(arr, obj) {
return arr.map(item => {
if (item.name === obj.name) {
return arr
} else if (item.children) {
return findDeep(item.children, obj)
} else {
return undefined
}
}).reduce((prev, curr) => {
console.log('prev: ', prev)
console.log('curr: ', curr)
return prev || curr
})
}
应用于此对象:
const mockApps = {
name: 'orange',
children: [{
name: 'white'
}, {
name: 'green',
children: [{
name: 'yellow',
children: [{
name: 'red'
}, {
name: 'white'
}]
}, {
name: 'green',
children: [{
name: 'purple'
}]
}]
}, {
name: 'gray'
}]
}
const activeApp = {
name: 'purple',
color: 'purple',
path: 'writer'
}
findDeep(mockApps.children, activeApp)
我认为这种模式就像MDN中的例子:
[0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, currentIndex, array) {
return previousValue + currentValue;
});
但令我惊讶的是,我理论化的与输出不同:
我认为previousValue
将是上一次迭代的returnValue
,但正如您在控制台中看到的那样,即使prev
,第三个currentValue
也未定义之前的迭代不是。
这个reduce
功能的正确模式是什么?
这里是CodePen。
答案 0 :(得分:1)
您似乎假设控制台输出属于reduce
的一次运行,但事实并非如此。
函数findDeep
以递归方式调用自身,因此您可以从对reduce
的不同调用中获得输出。
我建议您按照以下方式修改代码,以便在调用和退出findDeep
时在控制台中查看:
function findDeep(arr, obj) {
console.log('Entering findDeep');
var res = arr.map(item => {
if (item.name === obj.name) {
return arr
} else if (item.children) {
return findDeep(item.children, obj)
} else {
return undefined
}
}).reduce((prev, curr) => {
console.log('prev: ' + JSON.stringify(prev));
console.log('curr: ' + JSON.stringify(curr));
console.log('return: ' + JSON.stringify(prev || curr));
return prev || curr;
});
console.log('Exiting from findDeep');
return res;
}
这应该为这个问题带来光明。这是一个将日志写入浏览器的片段:
console = { log: function(msg) {
document.write(msg + '<br>');
}}
function findDeep(arr, obj) {
console.log('Entering findDeep');
var res = arr.map(item => {
if (item.name === obj.name) {
return arr
} else if (item.children) {
return findDeep(item.children, obj)
} else {
return undefined
}
}).reduce((prev, curr) => {
console.log('prev: ' + JSON.stringify(prev));
console.log('curr: ' + JSON.stringify(curr));
console.log('return: ' + JSON.stringify(prev || curr));
return prev || curr;
});
console.log('Exiting from findDeep');
return res;
}
const mockApps = {
name: 'orange',
children: [{
name: 'white'
}, {
name: 'green',
children: [{
name: 'yellow',
children: [{
name: 'red'
}, {
name: 'white'
}]
}, {
name: 'green',
children: [{
name: 'purple'
}]
}]
}, {
name: 'gray'
}]
}
const activeApp = {
name: 'purple',
color: 'purple',
path: 'writer'
}
findDeep(mockApps.children, activeApp)
正如您所看到的,以前似乎prev
的值与前一次迭代的返回值不对应,现在很明显这两次迭代属于{{1}的不同调用},所以它的行为就像你期望的那样。
答案 1 :(得分:1)
如果您遵循代码,传递给 map (级别0)的第一个值是:
{name: 'white'}
它没有紫色或任何子项的名称,因此结果数组现在是:
[undefined]
下一项是:
{name: 'green',
children: [{
name: 'yellow',
children: [{
name: 'red'
}, {
name: 'white'
}]
}, {
name: 'green',
children: [{
name: 'purple'
}]
}]
}
它有一个 children 属性,因此它的值被传递给 findDeep (级别1)的递归调用,即:
[{
name: 'yellow',
children: [{
name: 'red'
}, {
name: 'white'
}]
}, {
name: 'green',
children: [{
name: 'purple'
}]
}]
传递给 map 的第一项,再次 findDeep 以递归方式调用(级别2):
[{name: 'red'},
{name: 'white'}]
}, {
name: 'green',
children: [{
name: 'purple'
}]
第一个项目没有紫色或子项的名称,所以此级别的地图数组现在是:
[undefined]
下一个项目相同,所以现在是:
[undefined, undefined]
下一个名称为“紫色”,因此它被添加到数组中:
[undefined, undefined,{name:'purple'}]
这是通过 reduce 运行的,它是在没有累加器的情况下调用的,所以前两个值作为 prev 和 cur 传递。由于 prev 是假的,因此 curr 的值将作为累加器返回,因此在下次调用时,值为 undefined 和{name:'purple'}
,所以它返回到1级地图,它的数组现在是:
[{name:'purple'}]
此级别中没有更多成员,因此传递给reduce。因为它是数组中唯一的成员,并且没有传入累加器,所以只返回它,因此1级结果是:
[{name:'purple'}]
级别0的最后一个成员也返回undefined,因此最终的0级数组是:
[{name:'purple'}, undefined]
传递给reduce的是两个值,分别是 prev 和 curr 。由于 prev 该对象不是假的,所以返回它并且最终结果是:
[{name:'purple'}]
请注意,如果您使用 JSON.stringify 查看对象和数组, undefined 将更改为“null”。