const queue = []; const chunks = str .replace(regex, (type) => { switch (type) { case '"string"': case '"undefined"': return '"__par__"'; case '"number"': case '"boolean"': case '["array-simple"]': case '[null]': return '__par__'; default: const prop = type.match(/(?<=\").+?(?=\")/)[0]; queue.push(prop); return type; } }) .split('__par__');
这样你就会得到chunks和props两个数组。chunks里包含了被分割的 JSON 字符串。以例子来说,两个数组分别如下
// chunks [ '{"name":"', '","status":"', '","working":"', '"}' ] // props [ 'name', 'status', 'working' ]
最后,由于 map 中保存了属性名与访问路径的映射,因此可以根据 prop 访问到对象中某个属性的值,循环遍历数组,将其与对应的 chunks 拼接即可。
从代码量和实现方式来看,这个方案会更轻便与巧妙,同时也不需要通过 Function、eval 等方式动态生成或执行函数。
4. 总结
虽然不同库的实现有差异,但从整体思路上来说,实现高性能 stringify 的方式都是一样的:
开发者定义 Object 的 JSON scheme;
stringify 库根据 scheme 生成对应的模版方法,模版方法里会对属性与值进行字符串拼接(显然,属性访问与字符串拼接的效率要高多了);
最后开发者调用返回的方法来 stringify Object 即可。
归根到底,它本质上是通过静态的结构信息将优化与分析前置了。
Tips
最后,还是想提一下
所有的 benchmark 只能作为一个参考,具体是否有性能提升、提升多少还是建议你在实际的业务中测试;
fast-json-stringify 中使用到了 Function 构造函数,因此建议不要将用户输入直接用作 scheme,以防一些安全问题。