如何在JavaScript中序列化Map?替代JSON的高效方案
不用JSON序列化JavaScript Map的实用方法
嗨,这个问题我太有共鸣了!Map的迭代和计算性能确实比Object香不少,但序列化传递这块确实有点闹心——直接转JSON不仅麻烦,还容易丢失Map的特性(比如非字符串键)。下面给你几个原生、无依赖的序列化方案,按需选就行:
方案1:键值对拼接法(简单场景首选)
这个方法核心是把Map转成键值对数组,再用自定义分隔符拼接成字符串,解析的时候反向操作就行。好处是完全不碰JSON,代码极简。
// 序列化函数 function serializeMap(map) { // 用;分隔每个键值对,用|分隔键和值,注意选不会出现在你的键值里的字符 return Array.from(map.entries()).map(([key, value]) => `${key}|${value}`).join(';'); } // 反序列化函数 function deserializeMap(str) { if (!str.trim()) return new Map(); return new Map(str.split(';').map(item => { const [key, value] = item.split('|'); // 这里可以根据需求做类型转换,比如把字符串转数字/布尔 return [key, value]; })); } // 示例用法 const myMap = new Map([['name', 'Alice'], ['age', '28']]); const serialized = serializeMap(myMap); // "name|Alice;age|28" const deserialized = deserializeMap(serialized); // Map(2) {"name" => "Alice", "age" => "28"}
⚠️ 注意:如果你的键或值里包含你选的分隔符(比如|或;),记得先做转义,比如把|替换成\|,反序列化的时候再转回来,避免解析出错。
方案2:基于Map entries的JSON序列化(平衡简洁与兼容性)
虽然用到了JSON,但不是把Map转成普通Object,而是直接序列化它的entries()数组——这样既保留了Map的键类型(比如可以用数字、Symbol当键),反序列化也能直接用new Map()还原,完全不违背用Map的初衷。
// 序列化 function serializeMap(map) { return JSON.stringify(Array.from(map.entries())); } // 反序列化 function deserializeMap(str) { return new Map(JSON.parse(str)); } // 示例用法 const myMap = new Map([[123, 'numberKey'], [Symbol('foo'), 'symbolValue']]); const serialized = serializeMap(myMap); // "[[123,"numberKey"],["Symbol(foo)","symbolValue"]]" const deserialized = deserializeMap(serialized); // Map(2) {123 => "numberKey", Symbol(foo) => "symbolValue"}
这个方案几乎能覆盖90%的日常场景,代码量最少,还能处理非字符串键,非常省心。
方案3:递归序列化嵌套Map(复杂场景)
如果你的Map里嵌套了其他Map或者复杂对象,可以用递归的方式标记嵌套Map,确保反序列化时能正确还原结构。
// 递归序列化 function serializeMap(map) { return JSON.stringify(Array.from(map.entries()).map(([key, value]) => { // 标记嵌套的Map,用特殊前缀识别 if (value instanceof Map) { return [key, ['__MAP_MARKER__', serializeMap(value)]]; } // 如果是普通对象,直接保留,JSON能处理 return [key, value]; })); } // 递归反序列化 function deserializeMap(str) { const entries = JSON.parse(str).map(([key, value]) => { // 识别标记的嵌套Map,递归解析 if (Array.isArray(value) && value[0] === '__MAP_MARKER__') { return [key, deserializeMap(value[1])]; } return [key, value]; }); return new Map(entries); } // 示例用法 const nestedMap = new Map([['user', new Map([['name', 'Bob'], ['settings', new Map([['darkMode', true]])]])]]); const serialized = serializeMap(nestedMap); const deserialized = deserializeMap(serialized); // 完美还原嵌套Map结构
这个方案能处理复杂的嵌套场景,灵活性拉满。
总结
- 简单字符串/数字键值对:选方案1,完全脱离JSON
- 需要保留非字符串键或中等复杂度结构:选方案2,简洁又靠谱
- 有嵌套Map或复杂对象:选方案3,递归处理全覆盖
内容的提问来源于stack exchange,提问作者Pavlin Petkov
相关产品推荐
相关产品推荐

