Object.fromEntries 不解码 URL 参数,直接使用 URLSearchParams 会导致中文乱码、+变空格等问题;正确做法是先用 decodeURIComponent 解码键值对,再处理重复 key(如转为数组)。
很多人一看到 Object.fromEntries 就想直接配 URLSearchParams 一行搞定,比如:Object.fromEntries(new URLSearchParams(location.search))。这在大多数情况下能跑通,但一旦 QueryString 里有中文、空格、加号或特殊符号(比如 q=前端+开发&tag=JavaScript%20ES6),就会得到错误解码结果——+ 变成空格、%20 不被识别、中文直接乱码。
根本原因是:URLSearchParams 构造函数内部**只对 = 和 & 做分割,不对值做 decodeURIComponent;而浏览器自动调用的 toString() 或迭代时的 .get() 方法才触发解码。所以直接传给 Object.fromEntries 的是原始未解码字符串。
Array.from(searchParams.entries()).map(([k, v]) => [k, decodeURIComponent(v)])
Object.fromEntries(searchParams)(隐式调用迭代器,但 entry 值仍是 raw 字符串)searchParams.get(k) 是解码后的,但不能直接用于 fromEntries,因为你要的是键值对数组,不是单个值QueryString 允许同一个 key 出现多次,比如筛选标签:?tag=react&tag=vue&tag=nextjs。默认用 URLSearchParams 迭代会把后一个覆盖前一个,最终只剩 { tag: "nextjs" } —— 这通常不是你想要的。
得先决定业务逻辑:是取第一个?合并为数组?还是用逗号拼接?
searchParams.getAll("tag"),再手动构造数组项Object.fromEntries(Array.from(searchParams.keys()).map(key => [key, searchParams.getAll(key)]))
searchParams.entries() 每次只返回一个 key-value 对,不会自动聚合重复 keyObject.fromEntries 在 Node.js 12+、Chrome 73+、Firefox 63+、Safari 12.1+ 支持。如果你的应用要跑在微信内置浏览器(旧版 X5 内核)、IE 或某些国产安卓 WebView 里,大概率不支持。
别急着上 polyfill —— 先确认是否真需要。很多场景下,用 Object.assign(...) 或 reduce 更轻量:
const fromEntries = (entries) => entries.reduce((acc, [k, v]) => { acc[k] = v; return acc; }, {});
如果项目已用 Babel 或 Webpack,也可以配 @babel/polyfill 或 core-js/stable/object/from-entries,但要注意它只补方法,不修复 URLSearchParams 的编码行为。
把解码、去重、多值处理都收口到一个函数里,比每次手写更可靠。下面这个版本默认将重复 key 转为数组,单值保持原样,且严格解码:
function parseQuery(search) { const params = new URLSearchParams(search); const result = {}; for (const [key, value] of params.entries()) { const decodedKey = decodeURIComponent(key); const decodedValue = decodeURIComponent(value); if (result[decodedKey] !== undefined) { if (!Array.isArray(result[decodedKey])) { result[decodedKey] = [result[decodedKey]]; } result[decodedKey].push(decodedValue); } else { result[decodedKey] = decodedValue; } } return result;}
调用:parseQuery("?name=%E5%BC%A0%E4%B8%89&tag=web&tag=js") → { name: "张三", tag: ["web", "js"] }
这个实现绕开了 Object.fromEntries 的陷阱,也避免了 URLSearchParams 自动合并的副作用。真正复杂的地方不在语法,而在你是否意识到 QueryString 的语义边界和编码责任归属。