在前一篇博文中我介紹了一種可以讓JavaScript多少具備一點類似Lambda表達式的編程能力的辦法,但是由於要兼容於JavaScript的語法檢查,所以可以使用的場合也很有限。
不過有些比較細心的朋友可能發現了,我在那個(偽)Lambda模塊中使用了幾個小技巧,現在我就把這幾個小技巧介紹一下:
1、使用new Function來進行語法檢查。
嘗試寫框架的同學們一定對此感受頗深:有的時候通過代碼產生的代碼可能因為技術上的失誤而產語法錯誤,導致運行過程中異常中斷;有的時候需要接受用戶的輸入,但用戶可能有意或者無意地寫入有誤的語句或表達式。
有些同學為了解決這種問題特意去編寫(或者使用現成的)復雜的語法檢查過程——但編寫用來分析代碼語法的代碼是一件極其痛苦的事情,一旦發現問題調整起來也非常不方便。
其實這個問題有簡單一點的解決辦法,就是使用腳本引擎自己的語法檢查,比方說eval或者new Function——當然這個eval是不能亂用的,在不適當的時候用了eval的話整個程序都會出問題的;而new Function就沒這麼大問題——雖然說new Function在任何情況下構造的函數都是在全局作用域下直接工作的,但只是語法檢查的話並不會因為作用域問題而產生意外結果,只要你不真的直接調用通過它構造的新函數。
2、在eval接受的參數前面增加“0,”。
其實這是由於IE中存在一個BUG。
出於某種神奇的原因,如果你在IE中想通過調用eval來動態地構造一個函數的話,如果只是在函數的表達式兩邊增加括號——例如:
復制代碼 代碼如下:
eval('(function(){ /* code here */ })');
得到的返回也仍然是undefined,而其它浏覽器則會正確地返回這個新構造的函數的引用。
經過小小的探索之後,我發現最簡單有效的解決問題的辦法就是在前邊加上“0,” ,這樣就在所有(或者說,至少是現在的五大主流)浏覽器中都能得到預期結果了。
復制代碼 代碼如下:
eval('0,function(){ /* code here */ }');
注:在IE9的Chakra引擎中這個問題已經解決了~
3、使用數組對象的concat方法來產生新數組。 認真的說這個應該屬於JavaScript的常識,畢竟這個方法的用法在任何一個JavaScript語言功能參考上都能找到。
但是可能有些同學總是想不起來什麼時候可以用它。
在我的(偽) Lambda模塊中,我很無聊地編寫了一個可以把一個引用/值以多種別名同時附加在多個對象上的函數,這個函數既可以接受一個對象作為參數,也可以接受包含一系列對象的數組作為參數。
由於這個函數被調用的次數比較少,所以我決定用(不一定效率最好,但)簡單有效的辦法來適應兩種情況,也就是把單個對象參數轉化為只包含一個元素的數組再來處理,我選擇了用“[].concat(o)”的形式。
如果你有閱讀我的代碼,你可能會發現注釋中還包含了另一種方式,也就是“if (!(o instanceof Array)) o = [o]” ——後來我想了想,覺得一來不夠嚴謹(和ECMAScript 5中的isArray相比),二來調用的次數比較少,性能提升也很有限,就選擇了前一種。
在閱讀本文的同學們,你們有沒有什麼有趣的技巧可以分享給大家呢?