【面试题库】模板引擎

537 阅读1分钟

目录

  1. 模板引擎
  2. new Function('参数','函数体'); 动态创建函数体
  3. 模板渲染函数
  4. 编译过程

一、模板引擎

为了实现视图与业务逻辑的分离,无论MVP、MVVM、MVC那个V都会使用模板引擎。线面我们说说模板引擎的要求。

1) 需求

1.1) {{ }} 表达式

其实就是 将{{ }}中的值根据替换为表达式的结果。

模板结果
<b>{{ name }}</b><b>tom</b>
<b>{{ name.toUpperCase() }}</b><b>TOM</b>
<b>{{ '[' + name + ']' }}</b><b>[tom]</b>
1.2) 循环语句
{%arr.forEach(item => {%}
    <li>{{item}}</li>
{%})%}

生成

<li>aaa</li> 
<li>bbb</li>
1.3) 条件语句
{% if(isShow) { %} <b>{{ name }}</b> {% } %}

生成

<b>tom</b>

二、 new Function()动态创建函数体

需要一个我们不太常用的语法 new Function()用于动态创建函数体 比如

new Function('arg', 'console.log(arg + 1);');
// 相当于创建了一个匿名函数
function (arg) {
    console.log(arg + 1);
}

三、模板渲染函数

模板渲染的功能大概可以归纳为两步:

  1. 编译模板为Generate函数
  2. 执行渲染函数

比如最简单的模板

<b>{{ name }}</b>

生成后的渲染函数

generate(obj){
  let str = '';
  with(obj){
  str+=`<b>${name}</b>`}
  return str;
}

执行generate结果

const ret = generate({name : 'tom'}) 
// 运行结果: <b>tom</b>

四、 编译过程

我们把编译过程其实就是通过正则表达式的匹配

1) 第一步 插值表达式处理

{{ xxx }}表达式 转化为 ES6模板字符串 ${ xxx }

<b>{{ name }}</b> 转化为 "${name}"

let str = `<b>{{ name }}</b>`;

let templateStr = str.replace(/\{\{([^}]+)\}\}/g, function () {
    let key = arguments[1].trim();
    return "${" + key + "}";
});
console.log(templateStr); // "<b>${name}</b>"

2) 第二步 循环语句,分支语句处理

此处后续补充

五 简易模板引擎

function compile(str) {
    return obj => str.replace(/{{(.*?)}}/g, (_, s) => Function('obj', `with(obj) {return ${s};}`)(obj));
}

参考

总结

  • new Function('参数','函数体'); 动态创建函数体