JavaScript生成器函数未执行问题排查:无法生成数组全排列(含部分排列)
问题排查与修复方案
嘿,我一眼就揪出了你的代码里的核心问题——循环变量把元素和索引搞混了,这直接导致生成器完全没有产出任何值,测试自然也跑崩了!
到底哪里错了?
1. 循环变量误用是根源
你写的for (let i of arr),这里的i是数组的元素值,而不是你以为的索引!比如当输入是["a","b","c"]时,第一次循环i是"a",而不是0。
紧接着你用const value = arr[i],这就变成了arr["a"],结果肯定是undefined。后续的arr.indexOf(value) == i判断自然永远不成立(indexOf(undefined)返回-1,和"a"完全不相等),所以生成器里的yield代码块根本不会执行,自然没有任何值被产出。
2. 为什么断点没触发?
生成器是惰性执行的,只有当调用它的next()方法时才会开始运行(for...of循环会自动调用next())。但因为上面的错误,生成器没有任何产出,for...of循环直接跳过,你的生成器代码根本没机会执行,断点当然不会触发!测试里的expected数组完全没被消耗,最后长度还是15,这就说得通了。
修正后的生成器函数
把循环改成遍历索引,同时保留你原本的去重逻辑:
function* permute(arr) { if (arr.length === 1) { yield arr; return; } if (arr.length === 0) return; // 遍历索引而不是元素,这才是你需要的! for (let i = 0; i < arr.length; i++) { const value = arr[i]; // 跳过重复元素,避免生成重复排列 if (arr.indexOf(value) !== i) continue; // 产出单个元素的情况 yield [value]; // 生成剩余元素的排列并拼接 const others = arr.slice(0, i).concat(arr.slice(i + 1)); for (let perm of permute(others)) { yield [value, ...perm]; } } }
测试的小优化
你的测试逻辑没问题,但可以把生成器转成数组再和预期比较,这样更直观,也方便调试:
describe("Permute tests", () => { test("No duplicates", () => { const input = "abc".split(""); const expected = "a ab abc ac acb b ba bac bc bca c ca cab cb cba".split(" "); // 把生成器的产出转成数组 const result = Array.from(permute(input)).map(item => item.join("")); // 验证结果和预期完全匹配 expect(result).toEqual(expected); }); // 可以加个重复元素的测试用例,验证去重逻辑 test("With duplicate elements", () => { const input = ["a", "a"]; const expected = ["a", "a", "aa"]; const result = Array.from(permute(input)).map(item => item.join("")); expect(result).toEqual(expected); }); });
额外小建议
- 尽量用
===严格相等,避免隐式类型转换的坑。 - 数组为空时直接return,减少不必要的判断。
- 用
continue代替嵌套if块,代码可读性更好。
这样修改后,生成器就能正常产出所有唯一的部分排列,测试也能顺利通过啦!
内容的提问来源于stack exchange,提问作者Jeremy Hicks
相关产品推荐
相关产品推荐

