二話不說 輪子我都會造 還怕你面試問嗎? 一天造一個輪子,幹就完了。git
(計劃趕不上變化 隨時迭代 歡迎留言 隨時摸魚)github
爲了實現視圖與業務邏輯的分離,不管MVP、MVVM、MVC那個V都會使用模板引擎。線面咱們說說模板引擎的要求。面試
其實就是 將{{ }}中的值根據替換爲表達式的結果。正則表達式
模板 | 結果 | |
---|---|---|
<b>{{ name }}</b> |
→ | <b>tom</b> |
<b>{{ name.toUpperCase() }}</b> |
→ | <b>TOM</b> |
<b>{{ '[' + name + ']' }}</b> |
→ | <b>[tom]</b> |
用測試用例表示就是這樣算法
it("{{}} 表達式", () => {
const output = compile("<b>{{ name }}</b>")({ name: "tom" }); expect(output).toBe(`<b>tom</b>`); }); it("{{}} toUpperCase 表達式", () => { const output = compile("<b>{{ name.toUpperCase() }}</b>")({ name: "tom" }); expect(output).toBe(`<b>TOM</b>`); }); it("{{}} +鏈接", () => { const output = compile("<b>{{ '[' + name + ']' }}</b>")({ name: "tom" }); expect(output).toBe(`<b>[tom]</b>`); }); 複製代碼
{%arr.forEach(item => {%}
<li>{{item}}</li> {%})%} 複製代碼
生成結果設計模式
<li>aaa</li> <li>bbb</li> 複製代碼
{% if(isShow) { %} <b>{{ name }}</b> {% } %}
複製代碼
生成結果markdown
<b>tom</b>
複製代碼
模板渲染的功能大概能夠概括爲兩步:app
好比最簡單的模板框架
<b>{{ name }}</b>
複製代碼
生成後的渲染函數函數
generate(obj){
let str = ''; with(obj){ str+=`<b>${name}</b>`} return str; } 複製代碼
執行generate結果
const ret = generate({name : 'tom'})
// 運行結果: <b>tom</b> 複製代碼
咱們把編譯過程其實就是經過正則表達式的匹配
第一步 將{{ xxx }}表達式 轉化爲ES6模板字符串 ${ xxx }
// 全局正則表達式替換
template = template.replace(/\{\{([^}]+)\}\}/g, function () { let key = arguments[1].trim(); return "${" + key + "}"; }); 複製代碼
第二步 將{% %}表達式 轉化爲JS語句這樣的就能夠在模板中使用if、foreach了
好比if判斷:
{% if(isShow) { %} <b>{{ name }}</b> {% } %} // 轉化的函數 let str = ''; with(obj){ str+=`` if(isShow) { str+=`<b>${name}</b> ` } return str; 複製代碼
實現代碼
let head = `let str = '';\r\n with(obj){\r\n`;
head += "str+=`"; template = template.replace(/\{\%([^%]+)\%\}/g, function () { return "`\r\n" + arguments[1] + "\r\nstr+=`\r\n"; }); let tail = "`}\r\n return str;"; 複製代碼
這裏面須要一個咱們不太經常使用的語法 new Function()用於動態建立函數體 好比
new Function('arg', 'console.log(arg + 1);');
// 至關於建立了一個匿名函數 function (arg) { console.log(arg + 1); } 複製代碼
完整的代碼實現
template = template.replace(/\{\{([^}]+)\}\}/g, function () {
let key = arguments[1].trim(); return "${" + key + "}"; }); let head = `let str = '';\r\n with(obj){\r\n`; head += "str+=`"; template = template.replace(/\{\%([^%]+)\%\}/g, function () { return "`\r\n" + arguments[1] + "\r\nstr+=`\r\n"; }); let tail = "`}\r\n return str;"; console.log(`==========render=========`) console.log(head + template + tail); return new Function("obj", head + template + tail); 複製代碼
OK 任務完成
本文使用 mdnice 排版