JavaScript中,字符串反转算是一个常见的前端面试题了。下面由简单到复杂总结了几种方式。
1、for循环
说实话,这是最容易想到的方式了,因为不管是菜鸟还是高级前端,对for循环真的是烂熟于心,尽管高级的早已抛弃它。
function reverseString(str){
var res = new Array(),
len = str.length;
for(var i = (len-1); i >= 0; i--){
res.push(str.charAt(i));
}
return res.join("");
}
var str = "abcdefg";
console.log(reverseString(str)); // "gfedcba"
定义一个数组res,然后对str倒着循环,利用charAt()访问字符串某个索引上对应的项,push到数组中,然后将数组res转化成字符串返回。此方法不会改变原来的字符串。要是不牵扯到数组该怎么做呢?
function reverseString(str) {
var res = "",
len = str.length - 1;
for (var i = len; i >= 0; i--) {
res += str.charAt(i);
}
return res;
}
var str = "abcdefg";
console.log(reverseString(str)); // "gfedcba"
上面代码中的charAt()方法也可用substr(i, 1),substring(i, i+1),slice(i, i+1)来代替,这三个方法是字符串中很常用的方法,而且差别细微,有必要研究一下QAQ。
2、map()或forEach()函数循环
既然有循环的方法,那么自然就想到map()和forEach()了,不过IE8及以下低版本不支持这两个方法。既然它们是数组方法,那么要先将字符串转化成数组。下面以map()为例:
function reverseString(str){
var res = new Array();
str.split("").map(function(item, index, array){
res.unshift(item);
});
return res.join("");
}
var str = "abcdefg";
console.log(reverseString(str)); // "gfedcba"
在map()循环中,利用unshift()方法在数组头部添加项,由此最先添加的在数组后面,就像队列一样。
3、利用数组的反转方法reverse()
function reverseString(str){
str = str.split("");
str.reverse();
return str.join("");
}
var str = "abcdefg";
console.log(reverseString(str));
利用split()方法将字符串转化成数组,然后调用数组反转方法reverse(),代码比for循环简洁不少。此方法不会改变原来的字符串。上面代码看着咋有点别扭呢?split()结果赋值,调用reverse(),又在return语句中调用join(),知道了split()方法的返回值难道还需要一步一步赋值吗?看代码:
function reverseString(str){
return str.split("").reverse().join("");
}
哇,这么神奇,是不是嗅到了一点函数式编程的味道了,更不可思议的还在后面!
4、利用reduce()和reduceRight()两个方法实现
function reverseString(str){
return str.split("").reduce((prev, cur, index, array) => {return cur + prev});
}
var str = "abcdefg";
console.log(reverseString(str)); // "gfedcba"
又或者:
function reverseString(str){
return str.split("").reduceRight((prev, cur, index, array) => {return prev + cur});
}
var str = "abcdefg";
console.log(reverseString(str)); // "gfedcba"
这两个方法是数组的归并方法(具体介绍请看http://blog.csdn.net/zrn1812083198/article/details/79487641),很少有人会想到用它们实现这个反转功能,而且是ES6写法,这个比循环更为高级,可读性也非常高。
稍微成熟一点的前端开发工程师就会发现上面代码的一个诟病,是的,那就是都没有考虑到异常情况,这是很不可取的。不管是在面试中回答面试官的问题还是在实际项目中敲代码,逻辑考虑地是否周全非常重要,因为看上去非常美的代码,它的健壮性却很差,没办法百分百通过所有的情况。就像上面代码一样,假如向下面这样没有传递参数,结果是怎样的,你我都心知肚明。
reverseString(); // 这里相当于undefined
reverseString(null); // 这里是null, error, error中直接undefined变成null了
是的,惨不忍睹QAQ。
error, oh, my god。一切都白费了,看着如此美的代码,结果中看不中用。再比如:
reverseString(2);
这次说split不是一个函数,QAQ,太惨了。所以,该怎么优化一下呢?下面是一个考虑异常情况的简单例子:
function reverseString(str){
if(typeof str != "string"){
throw "The function needs an arguments of String";
}else if(str.length == 1){
return str;
}else{
return str.split("").reduce((prev, cur, index, array) => {return cur + prev});
}
}
这里接近尾声了,如果大家还有别的办法,不妨分享一下,互相学习。文中如有错误或不当的地方,烦请指正!