日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

underscore.js源码研究(5)

發布時間:2023/12/18 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 underscore.js源码研究(5) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概述

很早就想研究underscore源碼了,雖然underscore.js這個庫有些過時了,但是我還是想學習一下庫的架構,函數式編程以及常用方法的編寫這些方面的內容,又恰好沒什么其它要研究的了,所以就了結研究underscore源碼這一心愿吧。

underscore.js源碼研究(1)
underscore.js源碼研究(2)
underscore.js源碼研究(3)
underscore.js源碼研究(4)
underscore.js源碼研究(5)
underscore.js源碼研究(6)
underscore.js源碼研究(7)
underscore.js源碼研究(8)

參考資料:underscore.js官方注釋,undersercore 源碼分析,undersercore 源碼分析 segmentfault

模板引擎

之前就接觸過模板引擎,比如說template.js、handlebars.js、jade.js、nunjucks.js等等。后來學react的時候也接觸過jsx,當時我就感到很不可思議,竟然能夠把js中的變量甚至語句插入到html里面去,真的十分神奇。今天看underscore.js的源碼的時候也發現里面竟然有模板引擎,于是我就來研究研究模板引擎。

實現變量替換

說到模板引擎,一個最基本的特性就是能在html代碼中插入js的變量,下面我們來實現這種效果。

我們需要實現這種效果:

//定義一個模板 const tpl = 'hello {{name}}';//定義值 const data = {name: 'haha'};//渲染,最后content是name被替換過的html代碼 const output = render(tpl, data);

其實仔細理了一下效果的流程之后,感覺實現這個效果挺簡單的,就是用一個正則替換,把{{ name }}里面的值替換為data里面的數據就行了。

實現代碼如下:

//定義替換的正則表達式 const rule = /{{([\s\S]+?)}}/g;//render函數 function render(tpl, data) {return tpl.replace(rule, (matcher, p1) => {return data[p1];}) }

注意,由于rule里面只有一個括號,所以replace第二個參數的函數里面只有p1沒有p2。

變量替換改進

為了便于閱讀,我們需要模板可以寫成下面的形式。(name兩邊有空格)

//定義一個模板 const tpl = 'hello {{ name }}';

所以我們加一個去空格的函數,整個代碼如下:

//定義替換的正則表達式 const rule = /{{([\s\S]+?)}}/g;//render函數 function render(tpl, data) {return tpl.replace(rule, (matcher, p1) => {return data[p1.trim()];}) }

注意:trim函數只兼容IE9,如果要兼容IE9以下的話就需要pollyfill了。

支持語句

幾乎所有的模板引擎都支持寫入語句,比如像下面的寫法:

const tpl = 'Students:' +//注意這里只有一個大括號!!!'{ for(i = 0; i < data.students.length; i++) }' +'{{ data.students[i].name }}'; const data = {students: [{id: 1,name: ' haha '},{id: 2,name: ' yaya '}] }; const content = render(tpl, data);

我們希望上述代碼輸出:

Students: haha yaya

看起來非常復雜,可是我們用偽代碼分解一下執行過程就感覺有點簡單了:

//首先輸出Students: //然后執行下面的代碼 for(i = 0; i < data.students.length; i++) { //這里輸出students[i].name } //完畢

實際寫起來是這樣的:

//定義要輸出的內容 content = ''; content += 'Students:'; for(i = 0; i < data.students.length; i++) {content += 'data.students[i].name'; } //輸出整個content return content

可以看到,上面有這2個要點:

  • 變量的內容需要添加到content里面,但是語句的內容不需要添加到content里面。
  • 不是模板的內容要記錄位置,然后再通過這個位置添加到content里面。
  • 所以好好整理一下,我們首先需要語句的正則表達式,然后通過這個正則表達式按照上述規則進行替換,代碼如下:

    //為了方便,我們把規則封裝在一個對象里面 const rules = {//插值,對應變量interpolate: /{{([\s\S]+?)}}/,//邏輯,對應語句evaluate: /{([\s\S]+?)}/ }; //2個正則合在一起,先替換變量,再替換語句 const matcher = new RegExp([rules.interpolate.source,rules.evaluate.source ].join('|'), 'g');//render函數 function render(tpl, data) {let concating = 'let content = "";\n';let index = 0;//仍然是replace里面的第二個參數是函數的形式tpl.replace(matcher, (match, interpolate, evaluate, offset) => {//添加非模板的內容if (tpl.slice(index, offset)) {concating += 'content += "' + tpl.slice(index, offset) + '";\n';}//記錄偏移量index = offset + match.length;//變量需要添加到content里面if (interpolate) {concating += 'content +=' + interpolate + ';\n';//語句不需要添加到content里面,而且不要分號} else if (evaluate) {concating += evaluate + '\n';}})concating += 'return content;';//以concating為內容,定義一個函數,參數是objconst renderFunc = new Function('obj', concating);return renderFunc(data); }

    它生成的renderFunc函數的代碼如下圖所示:

    (function(obj /*``*/) { let content = ""; content += "Students:";for(i = 0; i < data.students.length; i++) content += data.students[i].name ; return content; })

    可以看到有一個缺點,就是for循環沒有大括號,這就導致它只執行下面的那條語句。如果要加大括號的話,就需要額外的規則,我們這里不討論。

    所以把上面所有的代碼加起來就是這樣的:

    //為了方便,我們把規則封裝在一個對象里面 const rules = {//插值,對應變量interpolate: /{{([\s\S]+?)}}/,//邏輯,對應語句evaluate: /{([\s\S]+?)}/ };//2個正則合在一起,先替換變量,再替換語句 const matcher = new RegExp([rules.interpolate.source,rules.evaluate.source ].join('|'), 'g');//定義模板和數據 const tpl = 'Students:' +//注意這里只有一個大括號!!!'{ for(i = 0; i < data.students.length; i++) }' +'{{ data.students[i].name }}'; const data = {students: [{id: 1,name: ' haha '},{id: 2,name: ' yaya '}] };//render函數 function render(tpl, data) {let concating = 'let content = "";\n';let index = 0;//仍然是replace里面的第二個參數是函數的形式tpl.replace(matcher, (match, interpolate, evaluate, offset) => {//添加非模板的內容if (tpl.slice(index, offset)) {concating += 'content += "' + tpl.slice(index, offset) + '";\n';}//記錄偏移量index = offset + match.length;//變量需要添加到content里面if (interpolate) {concating += 'content +=' + interpolate + ';\n';//語句不需要添加到content里面,而且不要分號} else if (evaluate) {concating += evaluate + '\n';}})concating += 'return content;';//以concating為內容,定義一個函數,參數是objconst renderFunc = new Function('obj', concating);return renderFunc(data); }//輸出,結果為Students: haha yaya console.log(render(tpl, data));

    可以看到,整個過程實際上是在拼接和替換字符串,然后利用Function接受字符串的情形生成函數,沒有其他的任何內容。

    在下一篇博文中我們會對這個小的模板引擎進行優化。

    轉載于:https://www.cnblogs.com/yangzhou33/p/8972394.html

    總結

    以上是生活随笔為你收集整理的underscore.js源码研究(5)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。