实现 js 模板引擎
实现 JavaScript 模板引擎的基本思路
模板引擎的核心功能是将动态数据嵌入静态模板中,生成最终的字符串。以下是实现一个简单模板引擎的关键步骤:
字符串替换法
使用正则表达式匹配占位符并替换为实际数据:
function render(template, data) {
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
return data[key] || '';
});
}
// 使用示例
const template = 'Hello, {{name}}!';
const data = { name: 'World' };
console.log(render(template, data)); // 输出: Hello, World!
函数构造法
通过 Function 构造函数动态生成渲染函数:
function compile(template) {
const evalExpr = /<%=(.+?)%>/g;
const expr = /<%([\s\S]+?)%>/g;
template = template
.replace(evalExpr, '`); \n echo( $1 ); \n echo(`')
.replace(expr, '`); \n $1 \n echo(`');
template = 'echo(`' + template + '`);';
let script =
`(function parse(data){
let output = "";
function echo(html){
output += html;
}
${template}
return output;
})`;
return new Function('data', script);
}
// 使用示例
const template = '<p>Hello, <%= name %>!</p>';
const render = compile(template);
console.log(render({ name: 'World' }));
支持条件判断和循环
扩展模板语法以支持逻辑控制:
function advancedCompile(template) {
const evalPattern = /<%=(.+?)%>/g;
const controlPattern = /<%([\s\S]+?)%>/g;
let code = 'let output=[];\nwith(data){\n';
let cursor = 0;
template.replace(controlPattern, (match, expr, offset) => {
code += template.slice(cursor, offset)
.replace(/"/g, '\\"')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/(^| )echo\(/g, '$1output.push(');
code += '");\n' + expr + '\noutput.push("';
cursor = offset + match.length;
return match;
});
code += template.slice(cursor)
.replace(/"/g, '\\"')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/(^| )echo\(/g, '$1output.push(');
code += '");\n}\nreturn output.join("");';
return new Function('data', code);
}
// 使用示例
const template = `
<% for(let i=0; i<users.length; i++) { %>
<li><%= users[i].name %></li>
<% } %>
`;
const render = advancedCompile(template);
const data = { users: [{name: 'Alice'}, {name: 'Bob'}] };
console.log(render(data));
性能优化考虑
对于生产环境使用的模板引擎,还需要考虑以下优化点:

- 预编译模板为函数缓存
- 添加XSS防护机制
- 支持模板继承和局部模板
- 实现更友好的错误提示
现代前端框架通常使用虚拟DOM或响应式系统替代传统模板引擎,但对于特定场景,自定义模板引擎仍有用武之地。






