URLSearchParams迭代器为何会跳过每隔一个的键值对?
URLSearchParams迭代时删除元素出现跳项的原因
先看你提供的函数代码:
const foo = (qs) => { const sp = new URLSearchParams(qs); console.log(`pre: ${sp}`); for (const [key, val] of sp.entries()) { console.log(`'${key}: ${val}'`); sp.delete(key); } console.log(`post: ${sp}`); } foo('a=1&b=2&c=3&d=4');
两种执行情况的输出
- 注释
sp.delete(key)时的输出:
pre: a=1&b=2&c=3&d=4 'a: 1' 'b: 2' 'c: 3' 'd: 4' post: a=1&b=2&c=3&d=4
- 取消注释后的输出:
pre: a=1&b=2&c=3&d=4 'a: 1' 'c: 3' post: b=2&d=4
为什么会跳过隔一个键?
核心原因是URLSearchParams的迭代器是实时绑定集合状态的,不是创建时的快照。迭代过程就像用指针挨个遍历元素:
- 初始集合是
[a, b, c, d],迭代器指针指向第一个元素a; - 遍历
a并删除它,此时集合变成[b, c, d],所有元素往前挪了一位; - 迭代器指针按规则移动到下一个位置(原本的索引1),但现在这个位置对应的是原来的第三个元素
c(因为b挪到了原来a的位置),于是直接跳过了b; - 遍历
c并删除它,集合变成[b, d],元素再次前移; - 指针继续移动到下一个位置(原本的索引3),已经超出了当前集合的长度,迭代直接结束。
就这样,b和d完全没被迭代到,自然也没被删除。
解决办法
如果要在迭代时删除所有元素,先把迭代器转换成数组快照,基于快照遍历就不会受集合实时修改的影响:
const foo = (qs) => { const sp = new URLSearchParams(qs); console.log(`pre: ${sp}`); // 用Array.from生成条目快照,再遍历 for (const [key, val] of Array.from(sp.entries())) { console.log(`'${key}: ${val}'`); sp.delete(key); } console.log(`post: ${sp}`); } foo('a=1&b=2&c=3&d=4');
执行后所有元素都会被删除,post输出为空字符串。
内容的提问来源于stack exchange,提问作者punkish
相关产品推荐
相关产品推荐

