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個要點:

  1. 變量的內容需要添加到content里面,但是語句的內容不需要添加到content里面。
  2. 不是模板的內容要記錄位置,然后再通過這個位置添加到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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/452817.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/452817.shtml
英文地址,請注明出處:http://en.pswp.cn/news/452817.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

人心散了、項目必然要敗

最近接手一個項目&#xff0c;是從半路上接過來的。按照常理&#xff0c;只要腦子沒被驢踢&#xff0c;是不會接人家的爛攤子的。我之所以接這個項目&#xff0c;一方面是因為這個項目中的開發人員是我部門的人&#xff08;本人是部門主管&#xff09;&#xff0c;另一方面是因…

國家自科委管文科學部認定的國內30種重要期刊

國家自科委管文科學部認定的國內30種重要期刊 A類刊物&#xff08;22種&#xff09; 1、管理科學學報&#xff08;雙月刊&#xff09; 2、系統工程理論與實踐&#xff08;月刊&#xff09; 3、管理世界&#xff08;月刊&#xff09; 4、數量經濟技術經濟研究&#xff08;月刊&a…

面向對象的四個要點

?把對象(object)作為融合了數據及在數據上的操作行為的統一的軟件構件?把所有對象都劃分成類(class)。?按照父類與子類的關系&#xff0c;把若干個相關類組成一個層次結構的系統。?對象彼此間僅能通過發送消息互相聯系。

Django二次開發對接FastDFS

1.自定義文件存儲器類 配置文件settings中加入如下配置 # 設置Django的文件存儲類、&#xff08;名字固定&#xff09; DEFAULT_FILE_STORAGEutils.fdfs.storage.FDFSStorage# 設置fdfs使用的client.conf文件路徑&#xff08;名字自己定義&#xff09; FDFS_CLIENT_CONF./util…

微信支付 java 集成案例_Spring Boot項目中集成微信支付v3

1. 前言最近忙的一批&#xff0c;難得今天有喘氣的機會就趕緊把最近在開發中的一些成果分享出來。前幾日分享了自己寫的一個微信支付V3的開發包payment-spring-boot-starter&#xff0c;就忙里偷閑完善了一波。期間給微信支付提交了6個BUG&#xff0c;跟微信支付的產品溝通了好…

單挑力扣(LeetCode)SQL題:1308. 不同性別每日分數總計

相信很多學習SQL的小伙伴都面臨這樣的困境&#xff0c;學習完書本上的SQL基礎知識后&#xff0c;一方面想測試下自己的水平&#xff1b;另一方面想進一步提升&#xff0c;卻不知道方法。 其實&#xff0c;對于技能型知識&#xff0c;我的觀點一貫都是&#xff1a;多練習、多實…

需求與范圍駕馭深刻反省總結

每天都在講范圍、說需求&#xff0c;真的到了想整理出點什么的時候&#xff0c;卻一下子不知從何說起。也許是熟悉麻痹癥吧。根據我的破經歷&#xff0c;在需求方面有幾個是最搞人的&#xff0c;只要我們方法得當&#xff0c;雖然不一定能夠完全駕馭&#xff0c;但起碼可以改善…

16. vim

vim編輯器是vi的升級版本&#xff0c;帶顏色顯示安裝yum install -y vim-enhanced將passwd文件復制到其他目錄下&#xff0c;vim后沒有顏色 一般模式上下左右方向鍵或kjhl四個鍵移動光標n方向鍵 向特定方向移動n位ctrl b 或 pageup 向上翻頁ctrl f 或 pagedown 向下翻頁0或sh…

軟件生命周期

軟件生命周期由軟件定義、軟件開發和運行維護 ( 也稱為軟件維護 )3 個時期組成&#xff0c;每個時期又進一步劃分成若干個 階段 。

Jmeter(三)_配置元件

HTTP Cookie Manager 用來存儲瀏覽器產生的用戶信息 Clear Cookies each Iteration&#xff1a;每次迭代請求&#xff0c;清空cookies&#xff0c;GUI中定義的任何cookie都不會被清除。Implementation&#xff1a;默認HC4CookieHandlerCookie Policy&#xff1a;將用于管理Cook…

山寨版項目管理經驗小結

不知道這個標題是否合適。 忙了互聯網&#xff0c;再忙作軟件&#xff0c;今天好不容易閑下來&#xff0c;寫點最近總結的一些經驗。最近在和北京幾家大的軟件公司的合作過程中&#xff0c;也許我所看到的&#xff0c;可能不代表全部&#xff0c;但是值得從事這個行業的人重視。…

Django項目--首頁靜態化

0前言 1.使用Celery生成靜態頁面 task.py中新增任務函數generate_static_index_html()&#xff0c;任務函數生成靜態頁面。 app.task def generate_static_index_html():產生首頁靜態頁面# 獲取商品的種類信息types GoodsType.objects.all()# 獲取首頁輪播商品信息goods_bann…

C語言指針,申請、釋放內存,線程

2019獨角獸企業重金招聘Python工程師標準>>> 1&#xff1a;普通情況下&#xff0c;C語言的指針是使用虛擬地址&#xff0c;并非物理地址&#xff1b; 2&#xff1a;C語言mallco函數可以根據輸入的值&#xff0c;申請一塊連續的內存&#xff1b;free&#xff08;*p&a…

Docker在Ubuntu16.04上安裝

轉自&#xff1a;http://blog.51cto.com/collen7788/2047800 1、添加Docker源 sudo apt-get update 2、增加CA證書 sudo apt-get install apt-transport-https ca-certificates 3、添加GPG Key(一種加密手段) sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:…

java偽協議_通過偽協議解決父頁面與iframe頁面通信的問題

我們經常會有父頁面與iframe頁面的操作&#xff0c;比如這個iframe里面的內容是js寫的。如以下代碼var iframe document.getElementById("iframe"),doc iframe.contentWindow.document;doc.open();doc.write("---------something------");doc.close();以…

Django項目--靜態首頁的數據緩存(設置、獲取、更新)

0 前言 將處理計算的結果先臨時保存起來&#xff0c;下次使用的時候可以先直接使用&#xff0c;如果沒有這個備份的數據&#xff0c;重新進行計算處理。 將緩存數據保存在內存中 &#xff08;本項目中保存在redis中&#xff09; cache注意事項&#xff1a; 1&#xff09;如果…

關于騰訊算法大賽

騰訊算法大賽 本文參考于我協會前會長吳師兄的文檔 騰訊社交廣告高校算法大賽是面向高校大學生的算法大賽&#xff0c;作為騰訊核心的廣告業務單元&#xff0c;騰訊社交廣告通過對海量社交數據進行深入分析&#xff0c;構建多樣廣告場景&#xff0c;與8億用戶連接對話。在大數據…

列表推導式

#麻煩辦法new_lst []for i in range(10): new_lst.append(i**2)print(new_lst)#簡單辦法print([i**2 for i in range(10)])# 小題下面列表中取余list_a [1,2,3,-5,20,-7]print([i%2 for i in list_a])# 30以內所有能被3整除的數print([won for won in range(30) if won%3 …

軟件過程

軟件過程是為了獲得高質量軟件所需要完成的一系列任務的框架&#xff0c;它規定了完成各項任務的工作步驟。 軟件過程描述為了開發出客戶需要的軟件&#xff0c;什么人&#xff08;who&#xff09;、在什么時候&#xff08;when&#xff09;、做什么事&#xff08;what&#x…