JavaScript字符串String和Array操作的有趣方法


Posted in Javascript onDecember 18, 2012

字符串和数组在程序编写过程中是十分常用的类型,因此程序语言都会将String和Array作为基本类型,并提供许多字符串和数组的方法来简化对字符串的操作。JavaScript里面也提供了String类型和Array类型,并且有很多基本的String方法和Array方法来方便地对字符串进行合并、查找、替换、截取等处理。

JavaScript作为一个脚本语言,又提供了一种动态解析运行的机制,而这特性,又让使得在String操作的时候出现一些结合使用Array的有趣方法。这些方法可能有些偏门有点奇怪,但有时在效率、可读性、复用性上表现得却更好。

重复字符串
常常我们想要把字符串多次打印出来(比如想要个分割线),我们就需要将一个字符串重复多次, 可惜JavaScript并没有提供类似repeat这样的方法。当然我们可以用循环来拼接出来,但是我们可以利用JavaScript中Array的join方法来实现repeat

function repeat(str, n) { 
var arr = new Array(n+1); 
return arr.join(str); 
} 
//output: 
//-------

利用n+1个Array元素产生的n个间隙,再以目标字符串来拼接,我们就能得到字符串重复的功能。
扩展String的prototype使方法应用于所有字符串
JavaScript的对象继承和方法寻找是基于原型链(prototype chain),所有使用着的字符串都可以说是继承于String的对象,我们可以为String对象的prototype添加方法或者属性,这样该方法就可以应用到所有我们使用的对象上了。比如上边的repeat方法,就可以改成:
String.prototype.repeat = function(n) { 
var arr = new Array(n+1); 
return arr.join(this); 
}; 
document.write('-'.repeat(21)); 
//output: 
//---------------------

然后,直接通过字符串调用repeat方法,就可以得到跟上边一样的结果。
这可以让我们实现对字符串方法的扩充,简洁对字符串的操作,但是这会“污染”了JavaScript的String,当代码被转到其他文件但是那个文件下并没有得到这段扩充,就可能会造成找不到该方法;另外,调用prototype扩展方法比直接调用方法要稍微“慢”一些,因为JavaScript会先去在字符串对象自身的方法中尝试寻找,再找到String的prototype的方法;再者也许在将来我们扩充的方法(比如repeat)变成了标准方法了,再使用这代码就会覆盖了标准方法,得到不一致的结果。

但是忽略这些考虑,扩充JavaScript标准类型的prototype还是会给编程带来许多的遍历。

用Array作StringBuilder
在很多高级语言中,加号(+)在字符串的操作中被赋予了更多的意义:作为字符串拼接的操作符。不过在Java和C#中,我们也知道如何频繁进行字符串拼接的操作,使用加号(+)就会产生效率问题,因此在这种情况下就会推荐使用StringBuilder。

JavaScript也支持使用加号(+)来进行字符串拼接,那么也会有存在效率问题呢。可是JavaScript并没有提供StringBuilder这样的类。

其实在Java,C#中使用StringBuilder时,我们多数也是用append方法,而很少会用insert。好在JavaScript的Array是不限大小自动增长的,所以我们就可以利用Array来做StringBuilder,最后再join空字符串来拼接出目标字符串。

var sb = []; 
for(var i = 0; i <=21; i++) { 
sb.push(i); 
} 
document.write(sb.join('')); 
//output: 
//0123456789101112131415161718192021

到底是用Array做StringBuilder还是直接字符串拼接,jsPerf上有过很多testcases比较两者的效率,但是因为初始值、环境、字符串长度等原因,所以结果不一。其实字符串内容不是很大,或者可以使用多个加号(+)组合在一起,那么字符串拼接还是可以的;若是在代码不同地方对同一字符串变量进行追加,那么可能使用Array配合join会更好。

用split替代字符串的子串查找和替换
在字符串的操作中,很常出现的就是想要从字符串中查找一个子字符串是否存在,然后截取出该字符串,抑或是将该子字符串替换成其它字符串。

比如给一个文件名,希望根据点(.)分割获取基本名和后缀名。先来看看使用标准String方法实现的这些操作:

function getBaseName(str) { 
var pos = str.lastIndexOf('.'); 
if(pos < 0)return str; 
return str.substring(0, pos); 
} 
function getExtension(str) { 
var pos = str.lastIndexOf('.'); 
if(pos < 0)return ''; 
return str.substr(pos+1); 
} 
var fileName = 'hello_world.js'; 
document.write(getBaseName(fileName)); 
document.write('<br />'); 
document.write(getExtension(fileName)); 
//output: 
//hello_world 
//js

(除了substr和substring外,JavaScript还有slice都可以用来获取字符串的子串,但也正是因为选择太多,常常让我在出现选择恐慌,还有位置是该不该+1,对负数是如何处理也让我揪心。)

之前看到可以通过join把数组变成字符串,也可以利用String的split的方法把字符串变成数组。对于上边取文件名及扩展名的问题,我们就可以根据“.”把文件名分裂成数组各个部分,那么假如得到的数字大于1(后缀名存在),则所得数字的最后一个元素就是文件的扩展名了:

function getBaseName(str) { 
var segs = str.split('.'); 
if(segs.length > 1) segs.pop(); 
return segs.join('.'); 
} 
function getExtension(str) { 
var segs = str.split('.'); 
if(segs.length <= 1)return ''; 
return segs.pop(); 
}

考虑到文件名中可能包含多个“.”,所以我们还是需要用“.”把除了最后一部分外的各个部分join回来。
看到可以对字符串先split再join,就可以想到,我们可以想到对于这两个方法的参数可以传入不同的字符串,这样就起到了代替String的replace方法进行子串替换的功能了,而且还是全局替换。
比如希望把所有的下划线(_)替换成横杠(-):
var str = 'hello_from_ider_to_world'.split('_').join('-'); 
document.write(str); 
//Output: 
// hello-from-ider-to-world

相对于String的replace方法,该方法的有点在于:可以实现全局替换;而若要让replace能够全局替换,则需要传入正则表达式对象(RegExp)而不能是字符串作为第一参数。

replace可接受RegExp、Function作为参数
很多人知道String的replace方法是用来替换字符串子串的,也可能知道它可以接受正则表达式作为第一参数,而且如何要替换所有出现的地方,就必须要用RegExp并包含global标记。
比如之前的替换操作,用replace就应该是:

var str = 'hello_from_ider_to_world'.replace(/_/g, '-'); 
document.write(str);

再比如很常用的trim方法,虽然JavaScript并没有提供我们也可以自己很快的实现:
String.prototype.trim = function() { 
return this.replace(/^\s+|\s+$/g, ''); 
};

我们知道正则表达式一个很强大的功能就是向后引用(Back Reference),实际上JavaScript的replace不仅在第一个参数内做向后引用,而且在替换字符串上,也可以进行向后引用,只是很多地方可能用反斜杠(\)加数字作为标示而JavaScript则是用美刀($)加数字作为标示。
var friends = 'friends of Ider, friend of Angie'; 
var result = friends.replace(/(friends?) of (\w+)/g, "$2's $1"); 
document.write(result); 
//output: 
//Ider's friends, Angie's friend

通过在替换字符串里面进行向后引用,我们很快就把“朋友 of 谁谁谁”变成了“谁谁谁的朋友”。如果还要更复杂点怎么办呢?没有关系,replace还能接受Function作为参数作为回调函数,其中函数的第一个参数是整个匹配中的字符串,之后每一个代表个个向后引用匹配的,函数的返回值则是作为替换的字符串。所以很多使用,函数参数都会用$0, $1, $2来表示。来看个例子:
var friends ="friends of mine, friend of her and friends of his"; 
var result = friends.replace(/(friends?) of (\w+)/g, 
function($0, $1, $2) { 
if($2 == 'mine') $2 = 'my'; 
return $2 + ' ' + $1; 
}); 
document.write(result); 
//output: 
//my friends, her friend and his friends

通过回调函数就可以实现很多很负责的字符串匹配了。至于效率,就先不考虑了。
Javascript 相关文章推荐
兼容IE和Firefox的javascript获取iframe文档内容的函数
Aug 15 Javascript
FireFox下XML对象转化成字符串的解决方法
Dec 09 Javascript
php图像生成函数之间的区别分析
Dec 06 Javascript
js实现简易的单数字随机抽奖(0-9)
Mar 19 Javascript
基于daterangepicker日历插件使用参数注意的问题
Aug 10 Javascript
vue如何获取点击事件源的方法
Aug 10 Javascript
Vue源码学习之初始化模块init.js解析
Nov 02 Javascript
Node之简单的前后端交互(实例讲解)
Nov 14 Javascript
js中null与空字符串&quot;&quot;的区别讲解
Jan 17 Javascript
深入解析koa之异步回调处理
Jun 17 Javascript
vue iview多张图片大图预览、缩放翻转
Jul 13 Javascript
vue 页面跳转的实现方式
Jan 12 Vue.js
学习js在线html(富文本,所见即所得)编辑器
Dec 18 #Javascript
javascript jscroll模拟html元素滚动条
Dec 18 #Javascript
Android中资源文件(非代码部分)的使用概览
Dec 18 #Javascript
js获取单选框或复选框值及操作
Dec 18 #Javascript
JQuery触发radio或checkbox的change事件
Dec 18 #Javascript
Jquery为单选框checkbox绑定单击click事件
Dec 18 #Javascript
jQuery实现form表单reset按钮重置清空表单功能
Dec 18 #Javascript
You might like
实现dedecms全站URL静态化改造的代码
2007/03/29 PHP
php模拟asp中的XmlHttpRequest实现http请求的代码
2011/03/24 PHP
php连接oracle数据库的方法(测试成功)
2016/05/26 PHP
Netbeans 8.2与PHP相关的新特性介绍
2016/10/08 PHP
PHP如何获取Cookie并实现模拟登录
2020/07/16 PHP
跟着Jquery API学Jquery之一 选择器
2010/04/07 Javascript
小试JQuery的AutoComplete插件
2011/05/04 Javascript
GridView中获取被点击行中的DropDownList和TextBox中的值
2013/07/18 Javascript
jquery trigger实现联动的方法
2016/02/29 Javascript
再谈Javascript中的异步以及如何异步
2016/08/19 Javascript
探究JavaScript中的五种事件处理程序方式
2016/12/07 Javascript
Javascript仿京东放大镜的效果
2017/03/01 Javascript
AngularJs 终极购物车(实例讲解)
2017/11/08 Javascript
JavaScript对象的浅拷贝与深拷贝实例分析
2018/07/25 Javascript
Vue登录拦截 登录后继续跳转指定页面的操作
2020/08/04 Javascript
vue 解决provide和inject响应的问题
2020/11/12 Javascript
vue+echarts实现中国地图流动效果(步骤详解)
2021/01/27 Vue.js
[51:28]EG vs Mineski 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/16 DOTA
[03:15]DOTA2-DPC中国联赛1月22日Recap集锦
2021/03/11 DOTA
状态机的概念和在Python下使用状态机的教程
2015/04/11 Python
Python实现删除列表中满足一定条件的元素示例
2017/06/12 Python
Python入门之后再看点什么好?
2018/03/05 Python
浅谈Python 列表字典赋值的陷阱
2019/01/20 Python
简单了解python的内存管理机制
2019/07/08 Python
详解python中的数据类型和控制流
2019/08/08 Python
Python GUI学习之登录系统界面篇
2019/08/21 Python
Python基于yield遍历多个可迭代对象
2020/03/12 Python
5 分钟读懂Python 中的 Hook 钩子函数
2020/12/09 Python
详解HTML5 data-* 自定义属性
2018/01/24 HTML / CSS
应届毕业生求职自荐书
2014/01/03 职场文书
班主任工作年限证明
2014/01/12 职场文书
幼儿教师师德承诺书
2014/05/23 职场文书
民主生活会批评与自我批评总结
2014/10/17 职场文书
2015年教师党员公开承诺书
2015/01/22 职场文书
Nginx 根据URL带的参数转发的实现
2021/04/01 Servers
JavaScript圣杯布局与双飞翼布局实现案例详解
2022/08/05 Javascript