1. 關於數組排序數組
排序一直是程序設計中的熱門話題。在js中,數組有個sort()方法。在不傳參數默認狀況下,數組的sort()方法原理是:對數每項調用toString()方法,比較字符串按升序排序數組。看下面的例子。函數
var arrA = [null, undefined, 3, 2, 5, 21, {toString:function() { return 1; }, p:'hello'}]; var arrB = [undefined, null, 3, 2, 5, 21,{toString:function() { return 1; }, p: 'hello'}]; var arrC = [null, undefined, 3, 2, 21, {toString:function() { return 1; }, p:'hello'}, {a:1}, {toString:function(){return 'p'}}, {toString:function(){return 'oa'}}, {toString:function(){return 'p'}}, {toString:function(){return 'v'}}, 'u', 'v', 'nukk','nulk' ]; arrA.sort();//結果是:[Object, 2, 21, 3, 5, null, undefined] arrB.sort();//結果是:[Object, 2, 21, 3, 5, null, undefined] arrA.sort()[0].p;//hello arrC.sort();
上面的例子說明:測試
a. sort()方法不傳比較函數時,的確是對每項調用了toString()方法[對null應該是使用String(null)]轉換成字符串再進行升序排序的this
b. undefined不會參與排序,直接放最後面spa
當要使用其它標準對數組進行排序時,就要傳入一個比較函數做爲參數。原理及執行過程沒有弄清楚(有知道的請告訴下),但獲得以下結論:prototype
var arrD = [3, 5, 1, 8, 10]; console.log(arrD.sort(compare)); function compare(v1, v2) { var a = v1; var b = v2; console.log('v1='+v1 + '||'+ 'v2='+v2); //return v1 - v2; //升序 //return v2 - v1;//降序 //return -1; //原樣輸出 //return 0; //原樣輸出 //return 1; //反順輸出 }
下面是一個實際Demo:設計
/** * 爲數組實現一個排序方法,可以num、string、date、character和object的排序, * 對object類型排序時,按照某個屬性排序。只考慮數組中存放都是相同類型的數據 * @param {Boolean} order 爲true表示升序,false表示降序 * @param {String} key 對象的鍵值 */ Array.prototype.sameTypeSort = function(order, key) { var type = type(this[0]); var ret = [], i = 0, temp, tempArr = []; order = order ? true : false; switch(type) { case 'string': ret = this.sort();//升序 break; case 'number': ret = this.sort(ascending); break; case 'date': while(temp = this[i]) { tempArr.push(temp.getTime()); i++; } tempArr.sort(ascending); break; default : while(i < this.length) { tempArr.push(this[i][key]); i++; } tempArr = tempArr.sameTypeSort(true); } //若是是時間,對象還要將還原成排序前的值 if(type === 'date') { i = 0; while(temp = tempArr[i]) { ret.push(new Date(temp)); i++; } } if(type === 'object') { i = 0; while(temp = tempArr[i]) { for(var start = 0, curObj, value; curObj = this[start]; start++) { value = curObj[key]; if(value === temp) { ret.push(curObj); break; } } i++; } } return order ? ret : ret.reverse(); function type(target) { return ({}).toString.call(target).slice(8, -1).toLocaleLowerCase(); } function ascending(v1, v2) { return v1 - v2; } };
下面是經過的Qunit的測試代碼:code
test( "數值排序", function() { var arr = [1,11,2,22,3,33,-5,-55, 0]; var upOrder = [-55, -5, 0, 1,2,3,11,22, 33]; propEqual(arr.sameTypeSort(true), upOrder, 'pass'); propEqual(arr.sameTypeSort(false), upOrder.reverse(), 'pass'); }); test( "字符串排序", function() { var arr = ['aa', 'ac', 'ab', 'bc', 'ba', 'acd']; var upOrder = ['aa', 'ab', 'ac', 'acd', 'ba', 'bc']; propEqual(arr.sameTypeSort(true), upOrder, 'pass'); propEqual(arr.sameTypeSort(false), upOrder.reverse(), 'pass'); }); test( "時間排序", function() { var arr = [new Date('2014/06/16 0:0:0'), new Date('2014/06/12 0:0:0'), new Date('2014/06/14 0:0:0')]; strictEqual(arr.sameTypeSort(true)[0].getTime(), arr[1].getTime()); strictEqual(arr.sameTypeSort(false)[0].getTime(), arr[0].getTime()); }); test( "對象排序", function() { var arr = [ {key:5, f: 'x'}, {key:2, f:'y'}, {key:6, f:'z'} ]; strictEqual(arr.sameTypeSort(true, 'key')[0].f, 'y'); strictEqual(arr.sameTypeSort(false, 'key')[0].f,'z'); console.log(arr.sameTypeSort(true, 'key')); console.log(arr.sameTypeSort(false, 'key')); });
2. match,replace函數練習orm
a. 價格千分對象
/** * 在整數部分對費用進行千分。一開始想用正則來作,但實現過程當中發現各類問題,最後代碼變成下面的樣子了 * @param {String} feeStr 有效的費用數值字符串 * @returns {String} 進行了千分格式化後的字符串 */ function splitFee(feeStr) { var ret, leftCtx, rightCtx; ponintPos = feeStr.indexOf('.'); if(ponintPos !== -1) { leftCtx = feeStr.substring(0, ponintPos); rightCtx = feeStr.substring(ponintPos+1); } else { leftCtx = feeStr; rightCtx = ''; } /*match = feeStr.match(/\./); leftCtx = RegExp.leftContext;//整數部分 rightCtx = RegExp.rightContext; 使用正則會有一個Bug,若後面match匹配失敗,後面的rightCtx始終會保存前次匹配的值*/ leftCtx = leftCtx ? leftCtx : feeStr; rightCtx = rightCtx ? '.'+rightCtx : ''; ret = (leftCtx.split('').reverse().join('').replace(/(\d{3})/g, function(m, ms, offset, targetStr) { return m + ',' }).split('').reverse().join('')+rightCtx).replace(/^\,/,''); return ret; }
經過的Qunit測試代碼
test( "replace, match練習:數值字符串千分", function() { //對整數部分進行千分 var fee1 = '1747136.51'; var fee2 = '277136.52'; var fee3 = '37136.53'; var fee4 = '47136'; var fee5 = '136'; strictEqual(splitFee(fee1), '1,747,136.51'); strictEqual(splitFee(fee2), '277,136.52'); strictEqual(splitFee(fee3), '37,136.53'); strictEqual(splitFee(fee4), '47,136'); strictEqual(splitFee(fee5), '136'); });
b. 交換包含兩個單詞的字符串
/** * 交換單詞字符串中的兩個單詞 * @param str * @returns {String} */ function swapTwoWords(str) { return str.replace(/(\w+)\s(\w+)/, '$2 $1'); //return str.split(' ').reverse().join(' '); 使用數組 } //Qunit測試 test( "replace練習:交換單詞", function() { var str = 'hello world'; strictEqual(swapTwoWords(str), 'world hello'); });
c. 字符串模板替換方法
/** * 字符串模板替換方法 * @param {String} str * @param {Object} obj */ function format(str, obj) { return str.replace(/({\w+})/gm, function(m, ms, offset, targetStr) { return obj[m.substring(1, m.length - 1)]; }); } //Qunit測試 test( "字符串模板format方法", function() { var str = '<div>{id}</div></div>{name}</div>'; strictEqual(format(str, {id:100, name:'xyz', address:'cd'}), '<div>100</div></div>xyz</div>'); });