7.3 案例实战
JavaScript预定义的方法很多,也非常强大,但是对于日益多样化的应用开发来说,还是很有限的。不过,可以根据日常开发的需要,把经常重用的代码封装为原型方法,以扩展String对象的应用。
7.3.1 修剪字符串
下面模拟VBScript字符串处理函数,为JavaScript的String对象扩展几个实用方法。
1.截取字符串左侧字符
在VBScript中,left()方法的语法如下:
result = left(string, length)
它包含两个参数,第一个是操作的字符串,第二个是截取的长度。该方法返回截取的子字符串。
【示例1】实现相同的功能,同时考虑到JavaScript语法习惯,可以这样设计:
var left = String.prototype.left = function(){ //定义静态方法left(),以及String对象的方法left() var l=arguments.length; //获取函数参数长度 if(l==0){ //如果没有参数 throw new Error("缺少参数。"); //则抛出异常 }else if(l==1){ //如果仅有一个参数,则视为String对象的方法 var n=arguments[0] //该参数值表示截取字符的长度 if(n>0){ //如果截取字符大于0 return this.substring( 0, n ); //则返回从字符串左侧开始截取的子字符串 }else if(n<1 ){ //如果小于1,则说明截取字符不够 return""; //则返回空字符串 }else{ //否则 throw new Error( "参数类型错误。" ); //抛出异常,提示参数类型不是数值型数据 } }else{ //如果参数长度大于1,则说明是静态方法 if((typeof arguments[0] =="string")&& (arguments[1] >0)){ //如果第一个参数类型为字符串,第二个参数值大于0,则通过调用参数字符串来进行截取 return arguments[0].substring( 0, arguments[1] ); //返回截取的子字符串 }else{ throw new Error( "参数类型错误。" ); //否则抛出异常,提示参数类型错误 } } }
在上面代码中,把left()方法定义为静态方法和对象方法两种形式。所谓静态方法,就是把函数直接传递给一个全局变量,这样就可以直接调用。所谓对象方法,就是把函数传递给String对象的原型属性上,这样只能够在字符串对象中进行调用。
考虑到用户在输入参数时,可能存在误输入,函数中设计了多种检测条件,如参数个数和参数类型,并根据参数个数和参数类型执行不同的操作。
作为静态方法直接调用:
var s = "javascript"; var s1=left(s,4); //静态方法调用 alert(s1); //返回字符串"java"
作为对象方法来进行调用:
var s = "javascript"; var s1=s.left(4); //对象方法调用 alert(s1); //返回字符串"java"
2.截取字符串右侧字符
在VBScript中,right()方法表示从字符串的尾部提取指定数目的字符,实际上它与left()方法是对应的。其实现的方法与上面的示例基本相同,只需要修改substring()截取子字符串的初始下标位置即可。具体说,就是把
return this.substring( 0, n );
修改为:
return this.substring( this.length - n );
把
return arguments[0].substring( 0, arguments[1] );
修改为:
return arguments[0].substring( arguments[0].length - arguments[1] );
其他代码不变。
3.清除字符串首尾的空格
trim()方法能够复制字符串并去掉首尾的空格。该方法能够匹配所有不可见字符,包括任何空白字符,如空格、制表符、换页符等。其语法格式如下:
result = trim(string)
【示例2】这个方法实现起来比较简单,可以使用正则表达式来进行快速匹配:
var trim = String.prototype.trim = function(){ //定义trim()方法的静态方法和对象方法 return ( arguments[0] ? arguments[0] : this ).toString(). replace( /(^\s*)|(\s*$)/gm, "" ); }
在该函数的返回表达式中,首先判断是否存在参数,如果存在参数,则使用第一个参数值,否则就使用this(指向当前对象)。然后,调用toString()方法把对象转换为字符串。最后,使用replace()进行匹配查找字符串首尾是否存在空格,并进行替换。匹配的正则表达式/(^\s*)|(\s*$)/gm说明如下。
“\s”表示空格,“^”表示字符串的开始处。
“$”表示字符串的结尾处。
“|”表示或的意思,即可以是字符串头部出现空格,或者尾部出现空格,或者同时出现等。
修饰字m表示多行匹配的意思。
而g表示连续匹配的意思。
var s=" javascript "; alert(s.length); //返回字符串长度为14 var s1=s.trim(); //清除两侧空格 alert(s1); //返回字符串"javascript" alert(s1.length); //返回字符串长度为10
测试发现应用trim()方法前后,字符串的长度是不同的,说明操作成功。
4.清除字符串左侧空格
lTrim()方法能够清除字符串左侧的空格。其实现方法与trim()方法基本相同,可以稍稍改动其中正则表达式的匹配模式。
【示例3】下面的函数定义了如何清除字符串左侧的空格。
var lTrim = String.prototype.lTrim = function(){ return ( arguments[0] ? arguments[0] : this ).toString(). replace( /^\s*/gm, "" ); }
其中正则表达式/^\s*/gm仅能够匹配字符串的左侧空格。
5.清除字符串右侧空格
rTrim()方法与lTrim()方法操作正好相反,它能够清除字符串右侧的空格。
【示例4】下面的函数定义了如何清除字符串右侧的空格。
var rTrim = String.prototype.rTrim = function(){ return ( arguments[0] ? arguments[0] : this ).toString(). replace( /\s*$/gm, "" ); }
其中正则表达式/\s*$/gm仅能够匹配字符串的右侧空格。
【示例5】如果要清除字符串中所有空格,包括字符串内部的,则可以使用如下方法来实现。
var allTrim = String.prototype.allTrim() = function(){ return ( arguments[0] ? arguments[0] : this ).toString(). replace( /\s*/gm, "" ); }
7.3.2 检测特殊字符
特殊字符检测和过滤是字符串操作中的常见任务。可以为String对象扩展一个方法check(),用来检测字符串中是否包含指定的特殊字符。
设计思路:方法check()的参数为任意长度和个数的特殊字符列表,检测的返回结果为布尔值。如果检测到任意指定的特殊字符,则返回true,否则返回false。
【示例】下面为字符串扩展一个原型方法check(),它能够根据参数检测字符串中是否存在特定字符。
String.prototype.check = function(){ //特殊字符检测,参数为特殊字符列表,返回true表示存在,否则不存在 if(arguments.length < 1) throw new Error("缺少参数"); //如果没有参数,则抛出异常 var a = [], _this = this; //定义空数组,并把检测的字符串存储在局部变量中 for(var i = 0 ; i < arguments.length; i ++ ){ //遍历参数,把参数列表转换为数组 a.push(arguments[i]); //把每个参数值推入数组 } var i=-1; //设置临时变量,初始化为-1 a.each(function(){ //调用数组的扩展方法each(),实现迭代数组,并为每个元素调用匿名函数,来检测字符串中是否存在指定的特殊字符 if(i! =-1)return true; //如果临时变量不等于-1,则提前返回true i=_this.search(this) //否则把检索到的字符串下标位置传递 }); if(i==-1){ //如果i等于-1,则返回false,说明没有检测到指定特殊字符 return false; }else{ //如果i不等于-1,则返回true,说明检测到指定的特殊字符 return true; } }
在该特殊字符检测的扩展方法中,使用了Array对象扩展的each()方法,该方法能够迭代数组。下面应用String对象的扩展方法check(),来检测字符串中是否包含特殊字符尖角号,以判断字符串中是否存在HTML标签。
var s='<script language="javascript"type="text/javascript">'; //定义字符串直接量 var b=s.check("<", ">"); //调用String对象的扩展方法,检测字符串 alert(b); //返回true,说明存在特殊的字符"<"或">",即存在标签
由于Array对象的扩展方法each()能够多层迭代数组。所以,还可以以数组的形式传递参数。例如:
var s='<script language="javascript"type="text/javascript">'; var a = ["<", ">", "\"", "\'", "\\", "\/", "\; ", "\|"]; var b = s.check(a); alert(b);
把特殊字符存储在数组中,这样更方便管理和引用。
7.3.3 优化字符串连接
在应用开发中,经常需要连接字符串进行输出。例如,通过JavaScript控制HTML标签在客户端输出。一般在连接字符串操作时都是使用加号运算符来实现的,但是当这种操作的字符串容量很大时,效率是非常低的。
【示例1】下面的代码演示了使用加号运算符连接字符串的方法。
var s="javascript", str=""; //定义一个字符串 var d=new Date(), a=d.getMilliseconds(); //获取当前毫秒数 for(var i=0; i<10000; i++) //循环连接字符串10000次 str += s; var d=new Date(), b=d.getMilliseconds(); //获取当前毫秒数 alert(b-a); //返回203毫秒,具体值会根据系统而略有不同
就这么一步操作,耗时203毫秒,如此操作的字符串非常大,那么这个时间消耗也是令人难以忍受的。但是如果改用数组来执行连接操作,执行效率会大幅提高。
【示例2】下面的代码演示了如何借助数组方法提升字符串的连接效率。
var s="javascript", a=[]; //定义一个字符串 var d=new Date(), b=d.getMilliseconds(); //获取当前毫秒数 for(var i=0; i<10000; i++) //循环执行10000次 a.push(s); //把字符串装入数组 var str=a.join(""); //通过join()方法把数组元素连接在一起 a=null; //清空数组 var d=new Date(), c=d.getMilliseconds(); //获取当前毫秒数 alert(c-b); //返回29毫秒
在上面示例中,通过把所有要连接的字符串装入数组,然后调用数组的join()把数组元素连接为字符串输出,这样执行效率大约能够提高10倍左右。如果操作的字符串巨大的话,通过数组中转来进行连接,则执行效率是非常明显的。当然,由于定义数组也会占用系统资源,使用完毕应该立即清除数组。所以,对于比较少的字符串连接操作来说,可以直接使用加号运算符来进行操作,当操作的字符串非常大时,可以考虑使用数组。