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 getElementsByName()的用法说明
Jul 31 Javascript
从零开始学习jQuery (三) 管理jQuery包装集
Feb 23 Javascript
基于jquery的loading 加载提示效果实现代码
Sep 01 Javascript
Javascript setInterval的两种调用方法(实例讲解)
Nov 29 Javascript
Javascript原型链和原型的一个误区
Oct 22 Javascript
JS+CSS实现仿触屏手机拨号盘界面及功能模拟完整实例
May 16 Javascript
jQuery实现带滚动导航效果的全屏滚动相册实例
Jun 19 Javascript
bootstrap模态框垂直居中效果
Dec 03 Javascript
Angularjs上传文件组件flowjs功能
Aug 07 Javascript
微信小程序拍照和摄像功能实现方法示例
Feb 01 Javascript
vue + typescript + 极验登录验证的实现方法
Jun 27 Javascript
探究一道价值25k的蚂蚁金服异步串行面试题
Aug 21 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基础知识:控制结构
2006/12/13 PHP
php模板原理讲解
2013/11/13 PHP
10个实用的PHP正则表达式汇总
2014/10/23 PHP
php实现将二维关联数组转换成字符串的方法详解
2017/07/31 PHP
PHP使用XMLWriter读写xml文件操作详解
2018/07/31 PHP
HTML TO JavaScript 转换
2006/06/26 Javascript
javascript 获取url参数和script标签中获取url参数函数代码
2010/01/22 Javascript
html5 canvas js(数字时钟)实例代码
2013/12/23 Javascript
使用JQuery FancyBox插件实现图片展示特效
2015/11/16 Javascript
BootStrap 智能表单实战系列(二)BootStrap支持的类型简介
2016/06/13 Javascript
利用jquery实现验证输入的是否是数字、小数,包含保留几位小数
2016/12/07 Javascript
TypeScript学习之强制类型的转换
2016/12/27 Javascript
详解Vue2 SSR 缓存 Api 数据
2017/11/20 Javascript
详解Node.js中的Async和Await函数
2018/02/22 Javascript
vue.js 嵌套循环、if判断、动态删除的实例
2018/03/07 Javascript
Vue项目中使用Vux的安装过程
2018/05/01 Javascript
vue.js绑定事件监听器示例【基于v-on事件绑定】
2018/07/07 Javascript
详解mpvue开发小程序小总结
2018/07/25 Javascript
vue2.0 如何在hash模式下实现微信分享
2019/01/22 Javascript
react 组件传值的三种方法
2019/06/03 Javascript
vue使用swiper实现中间大两边小的轮播图效果
2019/11/24 Javascript
js滚轮事件 js自定义滚动条的实现
2020/01/18 Javascript
[02:44]DOTA2英雄基础教程 魅惑魔女
2014/01/07 DOTA
python二叉树的实现实例
2013/11/21 Python
OpenCV-Python 摄像头实时检测人脸代码实例
2019/04/30 Python
关于Python Tkinter Button控件command传参问题的解决方式
2020/03/04 Python
HEMA英国:荷兰原创设计
2018/08/28 全球购物
Yummie官方网站:塑身衣和衣柜必需品
2019/10/29 全球购物
应聘教师推荐信
2013/10/31 职场文书
总经理任命书范本
2014/06/05 职场文书
项目委托协议书(最新)
2014/09/13 职场文书
学习群众路线的心得体会
2014/11/05 职场文书
公积金接收函格式
2015/01/30 职场文书
置业顾问岗位职责
2015/02/09 职场文书
辛德勒的名单观后感
2015/06/03 职场文书
你知道哪几种MYSQL的连接查询
2021/06/03 MySQL