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 相关文章推荐
让浏览器非阻塞加载javascript的几种方法小结
Apr 25 Javascript
JQuery 在文档中查找指定name的元素并移除的实现方法
May 19 Javascript
JavaScript ES6的新特性使用新方法定义Class
Jun 28 Javascript
微信小程序 MINA文件结构
Oct 17 Javascript
html判断当前页面是否在iframe中的实例
Nov 30 Javascript
Bootstrap基本插件学习笔记之折叠(22)
Dec 08 Javascript
vue-cli中打包图片路径错误的解决方法
Oct 26 Javascript
实例教学如何写vue插件
Nov 30 Javascript
vue全局使用axios的方法实例详解
Nov 22 Javascript
jQuery实现数字自动增加或者减少的动画效果示例
Dec 11 jQuery
JS实现数组删除指定元素功能示例
Jun 05 Javascript
vue 单页应用和多页应用的优劣
Oct 22 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 删除记录同时删除图片文件的实现代码
2010/05/12 PHP
一个比较不错的PHP日历类分享
2014/11/18 PHP
php实现遍历目录并删除指定文件中指定内容
2015/01/21 PHP
php基于GD库画五星红旗的方法
2015/02/24 PHP
php计算税后工资的方法
2015/07/28 PHP
PHP加密解密实例分析
2015/12/25 PHP
php查询及多条件查询
2017/02/26 PHP
php提取微信账单的有效信息
2018/10/01 PHP
使用laravel的migrate创建数据表的方法
2019/09/30 PHP
TP5框架页面跳转样式操作示例
2020/04/05 PHP
编写Js代码要注意的几条规则
2010/09/10 Javascript
js判断上传文件类型判断FileUpload文件类型代码
2014/05/20 Javascript
javascript中callee与caller的区别分析
2015/04/20 Javascript
jquery实现的缩略图预览滑块实例
2015/06/25 Javascript
举例讲解JavaScript substring()的使用方法
2015/11/09 Javascript
lhgcalendar时间插件限制只能选择三个月的实现方法
2017/07/03 Javascript
Vue实现一个返回顶部backToTop组件
2017/07/25 Javascript
babel的使用及安装配置教程
2018/02/22 Javascript
angularJs-$http实现百度搜索时的动态下拉框示例
2018/02/27 Javascript
js、jquery实现列表模糊搜索功能过程解析
2020/03/27 jQuery
基于JavaScript的数据结构队列动画实现示例解析
2020/08/06 Javascript
JavaScript实现复选框全选和取消全选
2020/11/20 Javascript
python实现unicode转中文及转换默认编码的方法
2017/04/29 Python
解决Mac安装scrapy失败的问题
2018/06/13 Python
Python实现将通信达.day文件读取为DataFrame
2018/12/22 Python
关于tensorflow的几种参数初始化方法小结
2020/01/04 Python
Selenium及python实现滚动操作多种方法
2020/07/21 Python
CSS3 media queries + jQuery实现响应式导航
2016/09/30 HTML / CSS
美国知名玩具品牌:Melissa & Doug
2016/08/16 全球购物
决定成败的关键——创业计划书
2014/01/24 职场文书
家长学校实施方案
2014/03/15 职场文书
创业者迈进成功第一步:如何写创业计划书?
2014/03/22 职场文书
小学教师个人先进事迹材料
2014/05/17 职场文书
2014年大学生党员评议表自我评价
2014/09/20 职场文书
2014小学数学教师个人工作总结
2014/12/18 职场文书
MySQL transaction事务安全示例讲解
2022/06/21 MySQL