JavaScript模板引擎_编译原理实现

JavaScript模板引擎通过词法分析将模板字符串拆分为文本、变量、逻辑等token,再经语法分析生成包含字符串拼接的可执行函数,利用new Function和with实现数据渲染,同时通过转义函数防范XSS风险,核心流程类似编译器的词法分析、语法分析与代码生成。

JavaScript模板引擎的实现,本质上是将带有占位符或逻辑语法的字符串转换为可执行的函数。这个过程涉及字符串解析、变量替换和代码生成,核心原理接近于简单的编译器工作流程:词法分析、语法分析、代码生成。

词法分析(Lexical Analysis)

模板字符串中包含普通文本和特殊语法,例如\表示逻辑代码,\表示变量输出。词法分析的任务是把整个模板字符串拆分成一个个有意义的“词法单元”(tokens)。

比如模板:

Hello, \

会被分解成:

  • 文本:"

    Hello, "

  • 变量插入:name
  • 文本:""

这一步通常通过正则表达式匹配来实现,逐个识别出插值、逻辑语句和普通文本片段。

语法分析与代码生成

在得到 tokens 后,下一步是生成对应的 JavaScript 函数体。目标是拼接出一个函数字符串,它使用字符串累加的方式构建最终 HTML。

常见做法是利用new Function动态创建函数。例如,上面的模板可以被编译成:

function(obj) {
var data = obj || {};
var out = '';
with(data) {
out += '

Hello, ' + name + '

';
}
return out;
}

关键点在于:

  • 使用out变量拼接结果
  • with语句让模板内可以直接访问数据属性
  • \转为+ expr +
  • \直接写入函数体,实现循环或条件判断

安全与转义处理

用户数据可能包含特殊字符,如>&,直接输出有 XSS 风险。因此需要提供转义输出语法,例如\

实现时可定义一个转义函数:

function escape(html) {
return String(html)
.replace(/&/g, '&')
.replace(/, 'zuojiankuohaophpcn')
.replace(/>/g, 'youjiankuohaophpcn')
.replace(/"/g, '"');
}

然后在生成代码时,将\转换为+ escape(name)

实际简化实现示例

以下是一个极简版模板引擎的核心逻辑:

function compile(template) {
const tpl = template
.replace(/[\r\t\n]/g, ' ')
.replace(/\/g, function(m, code) {
return '\'\n + ' + code.trim() + ' +\n \'';
})
.replace(/\/g, function(m, code) {
return '\';\n' + code.trim() + '\n out += \'';
});

const script = 'var out = \'' + tpl + '\'; return out;';
return new Function('obj', script);
}

使用方式:

const render = compile('

    \'
    + ''
    + '
  • \
  • '
    + ''
    + '
');

render({ list: ['a', 'b'] }); // 返回对应 HTML

基本上就这些。虽然现代框架多用虚拟 DOM,但理解模板引擎的编译过程有助于掌握动态代码生成和字符串处理的核心技巧。