javascript - 使用递归迭代数组的 Closure
问题描述
我试图用 clousure 做一个递归函数,但工作量不大。
我试图从数组中添加每个数字以最终返回 [1,2,3,4,5,6,7,8] 但只是返回我 [1,2,5] 奇怪的是我在里面放了一个 console.log否则它会打印我所有的数字。
你能解释一下为什么会这样吗
var array = [1, 2, [3, 4], 5, [6, [7, 8]]]; // --> 1,2,3,4,5,6,7,8
function recursiveArrayPrint(array) {
let resultado = []
return function iterator() {
for (let i = 0; array.length > i; i++) {
if (Array.isArray(array[i])) {
recursiveArrayPrint(array[i])()
} else {
console.log(array[i])
resultado.push(array[i])
}
}
return resultado
}
}
const test = recursiveArrayPrint(array);
console.log('test: ',test())
解决方案
程序中的错误
resultado
被声明在recursiveArrayPrint
- 在
iterator
你调用里面,每次都会recursiveArrayPrint
创建一个新的resultado
- 只有最外层
resultado
是return
ed
function recursiveArrayPrint(array) {
let resultado = [] // #1
return function iterator() {
for (let i = 0; array.length > i; i++) {
if (Array.isArray(array[i])) {
recursiveArrayPrint(array[i])() // #2
} else {
console.log(array[i])
resultado.push(array[i])
}
}
return resultado // #3
}
}
怎么修
function recursiveArrayPrint(array) {
// no need for resultado
function* iterator() { // use generator
for (let i = 0; array.length > i; i++) {
if (Array.isArray(array[i])) {
yield *recursiveArrayPrint(array[i]) // yield
} else {
yield array[i] // yield, not console.log
// no need for resultado
}
}
// no need for resultado
}
return iterator()
}
const arr = [1, 2, [3, 4], 5, [6, [7, 8]]]
for (const x of recursiveArrayPrint(arr))
console.log(x)
1
2
3
4
5
6
7
8
我们可以做得更好
recursiveArrayPrint
不是一个好名字。我们已经console.log
从迭代中解开了影响,调用者可以自由决定如何处理输出。我们可以直接调用recursiveArray
它- 内部函数
iterator
现在有点没用了。不再需要这种抽象 for
loop withi
很容易出错。我们可以使用for..of
循环以更清晰的方式编写它
function* recursiveArray(array)
{ for (const x of array)
if (Array.isArray(x))
yield *recursiveArray(x)
else
yield x
}
const arr = [1, 2, [3, 4], 5, [6, [7, 8]]]
for (const x of recursiveArray(arr))
console.log(x)
如果您希望将扁平数组作为返回值,JavaScript 提供了Array.from
将任何可迭代对象转换为数组的方法 -
console.log(Array.from(recursiveArray(arr)))
[1,2,3,4,5,6,7,8]
不仅适用于数组
- 我们可以重命名
recursiveArray
为traverse
,它可以作为通用函数运行 - 我们不是假设第一个输入是一个数组,而是先检查
isArray
然后再运行for..of
循环。否则简单地产生输入
function* traverse(t)
{ if (Array.isArray(t))
for (const x of t)
yield *traverse(x)
else
yield t
}
const arr = [1, 2, [3, 4], 5, [6, [7, 8]]]
for (const x of traverse(arr))
console.log(x)
1
2
3
4
5
6
7
8
从长远来看,编写健壮的函数将对您有所帮助。traverse
现在可以很容易地扩展为逐步遍历对象或其他可迭代对象。现在,当给出非数组输入而不是错误时,我们会得到一个合理的结果 -
for (const x of traverse(123))
console.log(x)
123
推荐阅读
- javascript - 如何正确地将状态传递给 React 中的不同函数?
- c# - 哪种方法限制内存使用:SqlReader.GetBytes 或 SqlReader.GetStream 用于大 blob?
- python - 尝试使用 TkAgg 后端进行绘图时,Mac OS 崩溃
- svg - 动画不规则 SVG 填充路径
- node.js - 如何在url中抓取
- mysql - 如何将 mysql 服务添加到 Consul docker 容器中?
- java - 将启动画面 img 更改为 mp4
- algorithm - 分割街道以创建多边形
- html - 为什么我的图片没有上传到我的 html 文件
- mysql - Amchart 中的 MYSQL PDO JOIN 问题