

順便也把John Resing 的寫法貼出來對比一下


我們可以注意到John Resig在替換簡單字元串的時候并不是利用的replace函數,而是使用的.split('xxx').join('')這樣的形式,乍一看我沒明白是什麼意思,類似這樣
仔細看了兩眼,達到的效果就是字元串替換,但是不明白為什麼複雜的(需要使用正規表達式的)使用replace,簡單的卻使用.split('XXX').join('')這樣的方式,莫非是執行效率問題?自己動手做了個例子驗證一下


不看不知道,一看吓一跳,如果我們希望replace方法替換字元串中所有指定字元串而不是隻替換一次,那麼就得往replace裡傳入正規表達式參數,并聲明全局屬性替換,這樣的話和.split('XXX').join('')效率上得差距還是有一些的,看看測試結果
圖中可以看出來,在一個并不是很複雜的字元串中替換三次,使用replace就有一定的劣勢了,當然我們實際用的時候不會像替換測試中使用9000000次,但這也算初步的一個優化工作了
一直以來都在中規中矩的這樣調用push方法
殊不知push方法可以傳入多個參數,按順序把參數放入數組,類似這樣
我們可以看到John Resig并不是簡單的把 <%=xxx%> 替換為 ');p.push(xxx);p.push(',而是通過
<% => \t
\t=xxx%> => ',$1,'
\t => ');
這樣達到了一次push函數放入多個參數,減少了push函數的調用次數,這樣原來拼接為


現在變成了下面内容,調用方法次數減少了,理論上也是可以在效率上有一定優化效果的(未測試)


過于為什麼拼接字元串使用push而不是+=應該是因為在低版本IE(IE 6-8)下頻繁調用字元串+=效率比較低,據可靠消息透露,其實在現代浏覽器中使用+=拼接字元串的效率是要比使用push高出不少的,是以這裡我們可以根據浏覽器不同使用不同的方式拼接字元串,在一定程度上優化模版引擎效率
在高版本(IE9+)和現代浏覽器上我們可以使用一套新的替換法則,使用+=拼接字元串而不是push方法,法則很簡單


我們當時為了解決作用域問題使用了with關鍵字,但是這個模版引擎的很大一部分效率問題正是猶豫with産生的,with的本意是減少鍵盤輸入。比如
可以簡寫成
但是,在實際運作時,解釋器會首先判斷obj.b和obj.d是否存在,如果不存在的話,再判斷全局變量b和d是否存在。這樣就導緻了低效率,而且可能會導緻意外,是以最好不要使用with語句。
在JavaScript中除了with,apply和call函數也可以改變JavaScript代碼執行環境,是以我們可以使用call函數,這樣因為使用with而導緻的性能問題就可以得到優化


我們可以看到John Resig在處理的時候加入了一個cache對象,并不是每次調用模版引擎的時候都會替換字元串,他會把每次解析的模版儲存下來,以備下次使用,我們之前讓模版引擎方法接受兩個參數分别是模版的id和資料源,John Resig使用的方法,第一個參數可以是id或者是模版内容,為了看清楚其作用,我們簡寫一下他的方法,去掉外層立即執行函數的部分


在調用tmpl方法的時候他會檢查第一個參數,如果參數中包含非單詞部分(空格回車神馬的),就認為其傳入的是模版内容,否則認為其傳入的是模版id(按照這個正規表達式,如果模版id中用 - 那麼也會被認為是模版内容,但是id中帶有-本身就很奇怪,如果有這種可能,可以改為 /[\W|-]/)。當傳入的是模版内容的時候執行剛才我們寫的new Function("obj",body)部分構造一個新函數;當傳入的是模版id的時候會判斷cache是否有緩存,如果沒有把根據id擷取的模版内容作為第一個參數傳入自身,再調用一次,把結果放入緩存。
這樣處理的效果就是每次我們調用模版的時候,如果傳入的是模版内容,那麼它會構造一個新的函數,如果使用的是模版id的話,第一次使用後會把構造好的方法放入緩存,這樣再次調用的時候就不用解析模版内容,生成新函數了。有同學可能會問,我們會重複調用模版方法嗎,很可能會,比如我寫了個模版是輸出一個學生資訊的模版,我想再頁面render一個班的學生資訊,可能就會使用模版數十次,隻是每次傳入的資料不同而已,是以這個優化還是很有必要的。簡單修改一下方法加上緩存功能


對比一下我們發現John Resig再構造新方法的時候多處理了幾個replace,主要是防止模版内容出現 ' ,這個東西會影響我們拼接字元串,是以先把它替換為換行符,處理完其它的後再把換行符轉換為轉義的' 即\\',說到這裡我們發現其實大神也難免有疏忽的時候,要是模版中有轉義字元\,也會對字元串拼接産生影響,是以我們需要多加一個置換 .split("\\").join("\\\\") 來消除轉義字元的影響。
當然不太明白大神代碼中的
這句是幹什麼用的,看起來好像是測試的代碼,可以删掉,有發現其它泳衣的同學告知一下啊
其實基本上也就是大神的原版上得一些改動
不是用with關鍵字處理作用域問題,使用call
添加處理轉義字元的置換語句
根據浏覽器不同來決定使用+=還是push方法拼接字元串(這個因為沒有想清楚是使用惰性載入函數還是針對浏覽器寫兩個函數開發者自己選擇調用,是以就不在代碼中展現了,有興趣同學可以使用自己覺得合适的方式實作)
對應現代浏覽器的版本大概是這樣的


雖然優化工作做完了,但這隻是最簡單的一個模版引擎,其它的一些強大的模版引擎不但在文法上支援注釋語句,甚至添加調試和報錯行數支援,這個并沒有處理這些内容,但我覺得在日常開發中已經夠用了。對于調試、報錯等方面有興趣的同學除了一些成熟的JavaScript模版引擎源碼可以看看下面兩篇文章會有一定幫助
<a href="http://ued.taobao.org/blog/?p=5469" target="_blank">http://news.cnblogs.com/n/139802/</a>
<a href="http://cdc.tencent.com/?p=5723" target="_blank">http://cdc.tencent.com/?p=5723</a>
本文轉自魏瓊東部落格園部落格,原文連結:http://www.cnblogs.com/dolphinX/p/3495256.html,如需轉載請自行聯系原作者