Underscore.js庫
你一天(一周)內寫了多少個循環了?
var i; for(i = 0; i < someArray.length; i++) { var someThing = someArray[i]; doSomeWorkOn(someThing); }
這當然無害,但這種寫法非常丑而且奇怪,這也不是真正需要抱怨的。但這種寫法太平庸了。
var i, j; for(i = 0; i < someArray.length; i++) { var someThing = someArray[i]; for(j = 0; j < someThing.stuff.length; j++) { doSomeWorkOn(someThing.stuff[j]); } }
你在擴展糟糕的代碼,在你拋出一大堆if前,你已經精神錯亂了。
我在兩年裡沒有寫一個循環(loop)。
“你在說什麼?”
這是真的,一個冷笑話。其實不是一個都沒有(好吧,我確實寫了幾個),因為我不寫循環(loops),我的代碼更容易理解。
怎麼做的呢?
_.each(someArray, function(someThing) { doSomeWorkOn(someThing); })
或者更好一點:
_.each(someArray, doSomeWorkOn);
這就是underscorejs所做到的。干淨,簡單,易讀,短,沒有中間變量,沒有成堆的分號,簡單非常優雅。
這是另外一些例子。
var i, result = []; for(i = 0; i < someArray.length; i++) { var someThing = someArray[i]; // 打到這,我已經手疼了 if(someThing.isAwesome === true) { result.push(someArray[i]); } }
同樣,一個使用循環浪費時間的典型用例。即便這些網站是宣傳禁煙和素食主義的,看到這些代碼我也感到義憤。看看簡單的寫法。
var result = _.filter(someArray, function(someThing) { return someThing.isAwesome === true; })
像underscore中的filter(過濾)的名字那樣,隨手寫的3行代碼就可以給你一個新的數組(array)。
或者你想把這些數組轉換成另外一種形式?
var result = _.map(someArray, function(someThing) { return trasformTheThing(someThing); })
上面三個例子在日常生活中已經夠用了,但這些功能還不足矣讓underscore放到台面上。
var grandTotal = 0, somePercentage = 1.07, severalNumbers = [33, 54, 42], i; // don't forget to hoist those indices; for(i = 0; i < severalNumbers.length; i++) { var aNumber = severalNumbers[i]; grandTotal += aNumber * somePercentage; }
underscore版本
var somePercentage = 1.07, severalNumbers = [33, 54, 42], grandTotal; grandTotal = _.reduce(severalNumbers, function(runningTotal, aNumber) { return runningTotal + (aNumber * somePercentage); }, 0)
這個剛開始看上去可能有點怪,我查了下關於reduce的文檔,知道了它的存在。因為我拒絕使用循環,所以它是我的首選。上面這些東西僅僅是入門,underscorejs庫還有一大堆牛B的功能。
30天不使用循環的挑戰。
在一下一個30天裡,不要使用任何循環,如果你看到一堆討厭和粗糙的東西,用each或者map將他們替換掉。再用一點reducing。
你需要注意到,Underscore是通往函數式編程的。一種看得見,看不見的方式。一條很好的途徑。
OurJS注*目前現代浏覽器已經支持each, filter, map, reduce方法,但underscore庫可以實現對舊版IE的兼容,下面是使用ES5原生方法寫的例子:
[3,4,5,3,3].forEach(function(obj){ console.log(obj); }); [1,2,3,4,5].filter(function(obj){ return obj < 3 }); [9,8,5,2,3,4,5].map(function(obj){ return obj + 2; }); [1,2,3,4,5].reduce(function(pre, cur, idx, arr) { console.log(idx); //4 個循環: 2-5 return pre + cur; }); //15 //sort方法同樣很有用 [9,8,5,2,3,4,5].sort(function(obj1, obj2){ return obj1 - obj2; });
for in與for loop
有人提出for in的效率要比for loop(循環)的效率低非常多。現在我們測試一下在不同浏覽器中使用for in, for loop和forEach在處理大數組時的效率究竟如何。
目前絕大部分開源軟件都會在for loop中緩存數組長度,因為普通觀點認為某些浏覽器Array.length每次都會重新計算數組長度,因此通常用臨時變量來事先存儲數組長度,如:
for (var idx = 0, len = testArray.length; idx < len; idx++) { //do sth. }
我們也會測試一下緩存與不緩存時的性能差異。
同時在每個測試循環中添加求和運算,來表明其不是空循環。
for (var idx = 0, len = testArray.length; idx < len; idx++) { //do sth. }
我們也會測試一下緩存與不緩存時的性能差異。
同時在每個測試循環中添加求和運算,來表明其不是空循環。
測試代碼如下,點擊運行即可查看
HTML 代碼
<h4 id="browser"></h4> <table id="results" class="table"></table>
JavaScript 代碼
function () { //准備測試數據, 有200萬條數據的大數組 var testArray = [] , testObject = {} , idx , len = 2000000 , tmp = 0 , $results = $("#results") , $browser = $("#browser") ; $browser.html(navigator.userAgent); $results.html(''); for (var i = 0; i < len; i++) { var number = Math.random(); //若希望加快運算速度可使用取整:Math.random() * 10 | 0 testArray.push(number); testObject[i] = number; } $results.append('<tr><th>測試代碼</th><th>計算結果</th><th>所需時間,毫秒</th></tr>'); //測試函數 var test = function(testFunc) { var startTime , endTime , result ; startTime = new Date(); tmp = 0; testFunc(); endTime = new Date(); //計算測試用例(Test Case)運行所需要的時間 result = endTime - startTime; $results.append('<tr><td><pre>{0}</pre></td><td>{1}</td><td>{2}</td></tr>'.format(testFunc.toString(), tmp | 0, result)); }; test(function() { //測試for in 的效率 for (idx in testArray) { tmp += testArray[idx]; //經測試,idx是string類型,可能是慢的原因之一 } }); test(function() { //測試for loop循環的效率 for (idx = 0, len = testArray.length; idx < len; idx++) { tmp += testArray[idx]; } }); test(function() { //測試forEach的效率 testArray.forEach(function(data) { tmp += data; }); }); test(function() { //測試不緩存Array.length時效率 for (idx = 0; idx < testArray.length; idx++) { tmp += testArray[idx]; } }); test(function() { //測試使用{} (Object) 存健值對時,使用for in的效率如何 for (idx in testObject) { tmp += testObject[idx]; } }); test(function() { //測試從{} Object查值時的效率如何(這裡的健key值事先己知) for (idx = 0, len = testArray.length; idx < len; idx++) { tmp += testObject[idx]; } }); }
運行 [需稍等片刻]
測試結果
測試結果可能因計算而異,這是在我機器上運行用,Firefox, Chrome, IE三者測試結果拼接的一張匯總。
以下是幾個觀察到的結論