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 相关文章推荐
Jquery调用webService远程访问出错的解决方法
May 21 Javascript
Jquery实现网页跳转或用命令打开指定网页的解决方法
Jul 09 Javascript
javascript:文字不间断向左移动的实例代码
Aug 08 Javascript
12个超实用的JQuery代码片段
Nov 02 Javascript
jquery表单提交带错误信息提示效果
Mar 09 Javascript
在一个页面实现两个zTree联动的方法
Dec 20 Javascript
jQuery实现手机号正则验证输入及自动填充空格功能
Jan 02 jQuery
vue 使用插槽分发内容操作示例【单个插槽、具名插槽、作用域插槽】
Mar 06 Javascript
vue动画—通过钩子函数实现半场动画操作
Aug 09 Javascript
js实现抽奖功能
Nov 24 Javascript
javascript实现左右缓动动画函数
Nov 25 Javascript
js 数组 fill() 填充方法
Nov 02 Javascript
学习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
php从csv文件读取数据并输出到网页的方法
2015/03/14 PHP
在Mac OS下搭建LNMP开发环境的步骤详解
2017/03/10 PHP
thinkPHP5.0框架配置格式、加载解析与读取方法
2017/03/17 PHP
针对thinkPHP5框架存储过程bug重写的存储过程扩展类完整实例
2018/06/16 PHP
CSS中简写属性要注意TRouBLe的顺序问题(避免踩坑)
2021/03/09 HTML / CSS
通用JS事件写法实现代码
2009/01/07 Javascript
jQuery获取地址栏参数插件(模仿C#)
2010/10/26 Javascript
鼠标滑上去后图片放大浮出效果的js代码
2011/05/28 Javascript
jQuery实现的导航条切换可显示隐藏
2014/10/22 Javascript
在浏览器中打开或关闭JavaScript的方法
2015/06/03 Javascript
JavaScript中对象的不同创建方法
2016/08/12 Javascript
jQuery中slidedown与slideup方法用法示例
2016/09/16 Javascript
Javascript实现一个简单的输入关键字添加标签效果实例
2017/06/01 Javascript
vue.js  父向子组件传参的实例代码
2017/10/29 Javascript
Vue-cli 使用json server在本地模拟请求数据的示例代码
2017/11/02 Javascript
Vue 幸运大转盘实现思路详解
2019/05/06 Javascript
JavaScript箭头函数中的this详解
2019/06/19 Javascript
NodeJS有难度的面试题(能答对几个)
2019/10/09 NodeJs
vue.js循环radio的实例
2019/11/07 Javascript
原生js实现贪吃蛇游戏
2020/10/26 Javascript
详解Vue3 Teleport 的实践及原理
2020/12/02 Vue.js
python实现图书馆研习室自动预约功能
2018/04/27 Python
ubuntu 16.04下python版本切换的方法
2019/06/14 Python
Python3列表List入门知识附实例
2020/02/09 Python
MAC平台基于Python Appium环境搭建过程图解
2020/08/13 Python
HTML利用九宫格原理进行网页布局
2020/03/13 HTML / CSS
介绍一下Java中的Class类
2015/04/10 面试题
大一新生学期自我评价
2014/04/09 职场文书
竞选班干部演讲稿
2014/04/24 职场文书
超市开店计划书
2014/04/26 职场文书
大学新闻系应届生求职信
2014/06/02 职场文书
拉拉队口号
2014/06/16 职场文书
2014学习十八届四中全会精神思想汇报范文
2014/10/23 职场文书
整脏治乱工作简报
2015/07/21 职场文书
《倍数和因数》教学反思
2016/02/23 职场文书
幼儿园2016年圣诞活动总结
2016/03/31 职场文书