你以为 Set 查询只能先转成数组再 includes?Chrome 154 今天把这件事在迭代器层面彻底原生化了
写过前端的都踩过这个坑:拿到一个 generator 函数,想查它里面有没有某个值——通常要 Array.from(gen()).includes(x),整趟迭代直接消费掉了。如果 generator 代表的是无限序列,这个写法直接卡死。
今天 Chrome 154 和 Firefox 154 把 Iterator.prototype.includes() 原生化,在迭代器层面做查询,不 materializing 整个序列。
Before:转数组再查
function* ids() {
yield 1;
yield 2;
yield 3;
}
// 以前:必须先全量展开成数组
const arr = Array.from(ids());
console.log(arr.includes(2)); // true
问题:无限 generator 无法用这个方法;大序列 materialization 内存开销大。
After:Iterator.prototype.includes()
function* ids() {
yield 1;
yield 2;
yield 3;
}
// Chrome 154+ / Firefox 154+:直接在迭代器上查
const iter = ids();
console.log(iter.includes(2)); // true
includes() 从迭代器头部开始扫描,遇到匹配即返回 true,遇到末尾才返回 false。不破坏迭代器状态(迭代器在匹配点或末尾就停止了)。
对于无限迭代器,只要匹配项在前面,就能立即返回,不需要展开整个序列:
function* fibonacci() {
let a = 0, b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
// 查前 100 个斐波那契数里有没有 89——不用展成长数组
const fib = fibonacci();
// includes 会停在找到匹配或迭代器耗尽时
console.log(fib.includes(89)); // true(89 在序列中)
落地检查清单
1. 兼容性: Chrome 154+ 稳定,Firefox 154+ 稳定,Safari 暂未实现。用 feature detection 保护:
if (typeof Iterator !== 'undefined' &&
typeof Iterator.prototype.includes === 'function') {
// 使用 includes
} else {
// fallback: [...iter].includes(x) 或手动迭代
}
2. 消费行为: includes() 会推进迭代器到匹配点或末尾,之后迭代器已耗尽,不能重用。需要注意这个副作用。
3. 性能注意: 匹配项越靠前越快;最坏情况(无匹配)需要完整扫描序列。
4. 搭配其他 Iterator helpers: includes() 可与 filter()、map() 等组合,实现声明式数据处理:
const result = [1, 2, 3, 4, 5].values()
.filter(x => x % 2 === 0)
.includes(4);
console.log(result); // true
下一步
把代码库里 Array.from(...).includes() 或 [...iter].includes() 的模式搜出来,评估是否换成 Iterator.prototype.includes()。注意不要用在必须保留迭代器状态的重用场景。
来源:Chrome 154 Release Notes(developer.chrome.com,2026-09-22)+ Firefox 154 Release Notes + TC39 Iterator Includes Proposal(github.com/tc39/proposal-iterator-includes)
评论区
登录后可评论。