本文介绍一种基于 Function 构造函数的安全模板变量替换方案,支持嵌套对象访问、默认值回退(||)、字符串字面量及 XSS 防护,避免 eval 风险并内置缓存优化。
本文介绍一种基于 `function` 构造函数的安全模板变量替换方案,支持嵌套对象访问、默认值回退(`||`)、字符串字面量及 xss 防护,避免 `eval` 风险并内置缓存优化。
在前端开发中,常需将 JavaScript 对象中的值动态注入 HTML 模板字符串(如 {{user.name}} 或 {{config.url || "/default"}})。但直接使用正则 + eval 存在严重安全隐患(作用域污染、XSS 注入、调试困难),而手动解析表达式又过于繁琐。推荐采用 new Function() + 作用域隔离 + HTML 转义 的组合方案,兼顾安全性、灵活性与性能。
以下是经过生产级优化的核心实现:
// 安全的 HTML 转义函数(防止 XSS)const escape = (str) => { if (str == null) return ''; const span = document.createElement('span'); span.textContent = str; return span.innerHTML;};// 主替换函数:支持嵌套属性、逻辑或回退、缓存加速const insertReplacements = (htmlStr, scope, cache = {}) => { // 将 scope 对象键名构造成形参列表,如 {uu, works} → 'uu,works' const argNames = Object.keys(scope).join(','); const args = `{${argNames}}`; return htmlStr.replace(/{{(.*?)}}/g, (_, expr) => { // 缓存已编译的表达式函数,避免重复解析 const fn = cache[expr] ??= new Function(args, `return ${expr}`); try { // 在严格限定的作用域内执行表达式 const value = fn(scope); // 默认对所有输出进行 HTML 转义(若需原生 HTML,请额外标记,如 {{!raw.html}}) return escape(value); } catch (e) { console.warn(`Template expression failed: "{{${expr}}}", error:`, e); return ''; } });};
使用示例:
const works = "It_works";const uu = { message: 'use this message here. <test>', learnMore: 'learn more', link: 'dai sit ein link', target: '_self', markup: '{{uu.message}} test: {{works}} <a data-cc="uu.link" target="{{uu.target}}" class="info" href="{{uu.link || "#null"}}">{{uu.learnMore}}</a>'};// ✅ 关键:传入扁平化作用域对象 {uu, works}const result = insertReplacements(uu.markup, { uu, works });console.log(result);// 输出:// "use this message here. <test> test: It_works <a data-cc="uu.link" target="_self" class="info" href="dai sit ein link">learn more</a>"
注意事项与最佳实践:
立即学习“Java免费学习笔记(深入)”;
该方案已在轻量级模板引擎和配置化 UI 渲染场景中验证,平衡了安全性、可维护性与运行效率,是替代 eval 的可靠选择。