实现一个简单的JavaScript解释器或模板引擎,核心是完成词法分析、语法解析和执行三个阶段的工作,下面我们以实现一个支持变量替换和简单表达式的模板引擎为例,逐步讲解实现过程。

核心概念说明
在实现之前,需要先了解两个基础概念:
- 词法分析:将输入的字符串拆分成一个个最小的语法单元,比如变量名、运算符、字符串等,这些单元被称为Token。
- 抽象语法树AST:将Token按照语法规则组织成树形结构,每个节点代表一个语法单元,方便后续执行。
实现简单的模板引擎
1. 词法分析阶段
我们的模板引擎支持{{ 表达式 }}的语法,首先需要将模板字符串拆分成普通文本和表达式两部分。
// 词法分析函数,将模板拆分为Token数组
function tokenize(template) {
const tokens = [];
// 匹配 {{ 表达式 }} 的正则
const reg = /{{(.+?)}}/g;
let lastIndex = 0;
let match;
// 遍历所有匹配的表达式
while ((match = reg.exec(template)) !== null) {
// 将表达式前的普通文本加入tokens
if (match.index > lastIndex) {
tokens.push({
type: 'text',
value: template.slice(lastIndex, match.index)
});
}
// 将表达式加入tokens,去除前后空格
tokens.push({
type: 'expression',
value: match[1].trim()
});
lastIndex = match.index + match[0].length;
}
// 处理最后剩余的普通文本
if (lastIndex < template.length) {
tokens.push({
type: 'text',
value: template.slice(lastIndex)
});
}
return tokens;
}
2. 语法解析与执行阶段
得到Token之后,我们需要将表达式转换为可执行的逻辑,这里为了简化实现,我们直接使用new Function来解析表达式,这种方式适合处理简单的变量和运算。
// 执行模板渲染
function render(template, data) {
const tokens = tokenize(template);
let result = '';
// 遍历所有Token,拼接结果
for (const token of tokens) {
if (token.type === 'text') {
// 普通文本直接拼接
result += token.value;
} else if (token.type === 'expression') {
// 表达式通过new Function解析,传入data作为上下文
try {
// 构造执行函数,将data的属性作为变量传入
const keys = Object.keys(data);
const values = Object.values(data);
// 函数参数为data的所有键,函数体返回表达式的值
const fn = new Function(...keys, `return ${token.value};`);
result += fn(...values);
} catch (e) {
// 表达式执行出错时返回空字符串
result += '';
}
}
}
return result;
}
3. 测试示例
我们编写测试用例验证模板引擎的功能:
// 测试模板
const template = '大家好,我是{{ name }},今年{{ age }}岁,明年我就{{ age + 1 }}岁了。';
// 测试数据
const data = {
name: '张三',
age: 20
};
// 执行渲染
const output = render(template, data);
console.log(output);
// 输出结果:大家好,我是张三,今年20岁,明年我就21岁了。
扩展:简单的JavaScript解释器思路
如果要实现更完整的JavaScript解释器,需要额外完成两个核心步骤:
- 语法解析:将Token转换为标准的AST结构,比如使用递归下降法解析赋值、运算、函数调用等语法。
- 执行器:遍历AST节点,根据节点类型执行对应逻辑,比如处理变量声明、运算符计算、流程控制等。
对于简单的解释器,我们可以先支持基础的数字运算和变量赋值,逐步扩展功能。比如下面的示例实现了两个数字相加的解释执行:
// 简单的加法解释执行示例
function interpretAddExpression(expr) {
// 解析表达式,假设格式为 a + b
const parts = expr.split('+').map(item => item.trim());
if (parts.length !== 2) {
throw new Error('不支持的表达式格式');
}
// 转换为数字计算
const a = Number(parts[0]);
const b = Number(parts[1]);
if (isNaN(a) || isNaN(b)) {
throw new Error('操作数必须是数字');
}
return a + b;
}
// 测试
console.log(interpretAddExpression('10 + 20')); // 输出 30
注意事项
实际生产环境中使用new Function存在一定的安全风险,如果模板内容来自不可信的用户输入,需要做好过滤和校验,避免注入攻击。如果是学习目的,这种方式可以快速验证解释器和模板引擎的核心逻辑,降低实现复杂度。
JavaScript解释器模板引擎AST修改时间:2026-07-18 09:54:29