60行代碼實現簡單的模板引擎
不久前看過一篇不錯的文章,作者用了15行代碼就實現了一個簡單的模板引擎,我覺得很有趣,建議在讀這篇文章之前先看一下這個,這裡是傳送門:只有20行的Javascript模板引擎
這個模板引擎實現的核心點是利用正則表達式來匹配到模板語法裡面的變數和JS語句,再將這些匹配到的欄位push到一個數組中,最後連接起來,用Function來解析字元串,最後將執行後的結果放到指定DOM節點的innerHTML裡面。
但是這個模板引擎還是有很多不足,比如不支持取余運算,不支持自定義模板語法,也不支持if、for、switch之外的JS語句,缺少HTML實體編碼。
恰好我這陣子也在看underscore源碼,於是就參考了一下underscore中template方法的實現。
這個是我參考template後實現的模板,一共只有60行代碼。
轉義
我們知道,在字元串中有一些特殊字元是需要轉義的,比如」『「, 『「『,不然就會和預期展示不一致,甚至是報錯,所以我們一般會用反斜杠來表示轉義,常見的轉義字元有
, ,
等等。
但是這裡的convertEscapes裡面我們為什麼要多加一個反斜杠呢?
這是因為在執行new Function裡面的語句時,也需要對字元進行一次轉義,可以看一下下面這行代碼:
這是因為Function函數在執行的時候,裡面的內容被解析成了這樣。
在JS裡面是不允許字元串換行出現的,只能使用轉義字元
。
正則表達式
underscore中摒棄了用正則表達式匹配for/if/switch/{/}等語句的做法,而是使用了不同的模板語法(和)來區分當前是變數還是JS語句,這樣雖然需要用戶自己區分語法,但是給開發者減少了很多不必要的麻煩,因為如果用正則來匹配,那麼後面就無法使用類似{# #}的語法了。
這裡正則表達式的重點是+?,+?是惰性匹配,表示以最少的次數匹配到[sS],所以我們//g是不會匹配到類似%>這種語法的,只會匹配到語法。
replace
這裡我們用到了replace第二個參數是函數的情況。
在JS正則表達式中,使用()包起來的叫著捕獲性分組,而使用(?:)的叫著非捕獲性分組,在replace的第二個參數是函數時,每次匹配都會執行一次這個函數,這個函數第一個參數是pattern匹配到的字元串,在這個裡面是」hello world」。
p1是第一個分組([a-z]+)匹配到的字元串,p2是第二個分組([a-z]+)匹配到的字元串,如果有更多的分組,那還會有更多參數p3, p4, p5等等,offset是最後一個參數,指的是在第幾個索引處匹配到了,這裡的offset是0,因為是從一開始就剛好匹配到了hello world。
字元串拼接
underscore中使用+=字元串拼接的方式代替了數組push的方式,這樣是因為+=相比push的性能會更高。
setting.variable
underscore這裡使用with來改變了作用域,但是with會導致性能比較差,關於with的弊端可以參考一下這篇文章: Javascript中的with關鍵字
你還可以在variable設置里指定一個變數名,這樣能顯著提升模板的渲染速度。不過語法也和之前有一些不同,模板裡面必須要用你指定的變數名來訪問,而不能直接用answer這種形式,這種形式下沒有使用with實現,所以性能會高很多。
如果喜歡這篇文章,請關注我的博客:http://ygy.online
參考鏈接:
js正則進階
JavaScript函數replace揭秘
JavaScript正則表達式分組模式:捕獲性分組與非捕獲性分組及前瞻後顧
underscore 系列之字元實體與 _.escape
Javascript中的with關鍵字


TAG:尹小耀的雜貨鋪 |