使用Array.reduce递归解析字符串触发栈溢出,问题出在哪?
问题分析与解决
你的代码触发栈溢出的核心原因是初始的字符串拆分方式破坏了大括号的完整性,导致递归逻辑陷入了无限循环:
错误根源拆解
- 当你执行
str.split(',')时,原字符串'React, {PureComponent, Fragment}'会被拆分为:
经过['React', ' {PureComponent', ' Fragment}']trim()处理后变成['React', '{PureComponent', 'Fragment}']。 - 处理第二个元素
'{PureComponent'时,它以{开头,但没有对应的},所以curr.indexOf("}")返回-1。 - 在JavaScript中,
substring(start, end)会把负数参数转为0,且如果start > end会自动交换两者位置,所以curr.substring(1, -1)等价于curr.substring(0, 1),得到的insideStr是'{'。 - 这个
'{'被拆分后传入递归的reduce调用,再次触发if (curr.charAt(0) === '{')分支,无限重复这个过程,最终导致栈溢出。
修复方案
方案1:简单场景(无嵌套大括号)—— 预处理字符串后拆分
如果你的场景只有一层大括号,不需要支持嵌套,最简单的方式是先移除所有大括号,再拆分:
const str = 'React, {PureComponent, Fragment}'; // 移除所有 { 和 } 字符 const cleanedStr = str.replace(/[{}]/g, ''); // 拆分并去除每个元素的空格 const result = cleanedStr.split(',').map(item => item.trim()); console.log(result); // ['React', 'PureComponent', 'Fragment']
方案2:支持嵌套大括号的递归解析(进阶)
如果需要处理更复杂的嵌套结构(比如'A, {B, {C, D}, E}'),你需要先正确识别完整的大括号块,再递归处理。这里提供一个修正后的递归reduce实现:
const str = 'React, {PureComponent, Fragment}'; const moduleFinder = (acc, curr) => { // 检查当前元素是否包含完整的 {} 对 if (curr.includes('{') && curr.includes('}')) { const insideStr = curr.slice(curr.indexOf('{') + 1, curr.indexOf('}')); const insideModules = insideStr.split(',').map(e => e.trim()); // 递归处理内部模块(如果有嵌套的话) return acc.concat(insideModules.reduce(moduleFinder, [])); } else if (!curr.includes('{') && !curr.includes('}')) { // 只处理不包含大括号的有效模块名 acc.push(curr); return acc; } else { // 如果元素只包含 { 或 },说明是被拆分的片段,直接忽略 return acc; } }; // 用正则匹配所有被逗号分隔的独立部分,包括完整的大括号块 const parts = str.match(/([^{},]+|\{[^{}]*\})/g).map(item => item.trim()); console.log(parts.reduce(moduleFinder, [])); // ['React', 'PureComponent', 'Fragment']
这里用正则/([^{},]+|\{[^{}]*\})/g来匹配所有独立部分:要么是不包含大括号和逗号的普通模块名,要么是完整的大括号块,避免了拆分大括号内的逗号,保证递归能正确处理。
内容的提问来源于stack exchange,提问作者MarksCode
相关产品推荐
相关产品推荐

