数组排序,字符串math,replace练习
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)]转换成字符串再进行升序排序的
b. undefined不会参与排序,直接放最后面
当要使用其它标准对数组进行排序时,就要传入一个比较函数作为参数。原理及执行过程没有弄清楚(有知道的请告诉下),但得到如下结论:
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的测试代码:
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函数练习
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>'); });