首页 » 编写高质量代码:改善JavaScript程序的188个建议 » 编写高质量代码:改善JavaScript程序的188个建议全文在线阅读

《编写高质量代码:改善JavaScript程序的188个建议》建议37:推荐使用replace

关灯直达底部

String对象的replace方法包含两个参数,第一个参数表示执行匹配的正则表达式,也可以传递字符串,第二个参数表示准备代替匹配的子字符串,例如,把字符串html替换为htm。


var b=s.replace(/"html/",/"htm/");


与search和match方法不同,replace方法不会把字符串转换为正则表达式对象,而是以字符串直接量的文本模式进行匹配。第二个参数可以是替换的文本,或者是生成替换文本的函数,把函数返回值作为替换文本来替换匹配文本。

replace方法同时执行查找和替换两个操作。该方法将在字符串中查找与正则表达式相匹配的子字符串,然后调用第二个参数值或替换函数替换这些子字符串。如果正则表达式具有全局性质,那么将替换所有的匹配子字符串,否则,只替换第一个匹配子字符串。

在replace方法中约定了一个特殊的字符“$”,如果这个美元符号附加了一个序号,就表示引用正则表达式中匹配的子表达式存储的字符串。例如:


var s=/"javascript/";

var b=s.replace(/(java)(script)/,/"$2-$1/");

alert(b);///"script-java/"


在上面的代码中,正则表达式/(java)(script)/中包含两对小括号,按顺序排列,其中第一对小括号表示第一个子表达式,第二对小括号表示第二个子表达式,在replace方法的参数中可以分别使用字符串/"$1/"和/"$2/"来表示对它们匹配文本的引用,当然它们不是标识符,仅是一个标记,所以不可以作为变量参与计算。除了上面约定之外,美元符号与其他特殊字符组合还可以包含更多的语义,详细说明如下:

❑$1、$2、…、$99:与正则表达式中的第1~99个子表达式相匹配的文本。

❑$&(美元符号+连字符):与正则表达式相匹配的子字符串。

❑$(美元符号+切换技能键):位于匹配子字符串左侧的文本。

❑$/'(美元符号+单引号):位于匹配子字符串右侧的文本。

❑$$:表示$符号。


var s=/"javascript/";

var b=s.replace(/.*/,/"$&$&/");///"javascriptjavascript/"


由于字符串“$&”在replace方法中被约定为正则表达式所匹配的文本,因此利用它可以重复引用匹配的文本,从而实现字符串重复显示效果。其中正则表达式“/.*/”表示完全匹配字符串。


var s=/"javascript/";

var b=s.replace(/script/,/"$&!=$/");///"javascript!=java/"


其中字符“$&”代表匹配子字符串“script”,字符“$”代表匹配文本左侧文本“java”。


var s=/"javascript/";

var b=s.replace(/java/,/"$&$/'is/");///"javascript is script/"


其中字符“$&”代表匹配子字符串“java”,字符“$/'”代表匹配文本右侧文本“script”。然后用“$&$/'is”所代表的字符串“javascript is”替换原字符串中的“java”子字符串,即组成一个新的字符串“javascript is script”。

在ECMAScript v3中明确规定,replace方法的第二个参数建议使用函数,而不是字符串(当然不是禁止使用),JavaScript 1.2实现了对这个特性的支持。这样,当replace方法执行匹配时,每次都会调用该函数,函数的返回值将作为替换文本执行匹配操作,同时函数可以接收以$为前缀的特殊字符组合,用来对匹配文本的相关信息进行引用。


var s=/'script language=/"javascript/"type=/"text/javascript/"/';

var f=function($1){

return$1.substring(0,1).toUpperCase+$1.substring(1);

}

var a=s.replace(/(bw+b)/g,f);

alert(a);//Script Language=/"JavaScript/"Type=/"Text/JavaScript/"


在上面的示例代码中,函数f的参数为特殊字符“$1”,它表示正则表达式/(bw+b)/中小括号每次匹配的文本。然后在函数体内对这个匹配文本进行处理,截取其首字母并转换为大写形式,之后返回新处理的字符串。replace方法能够在原文本中使用这个返回的新字符串替换每次匹配的子字符串。

对于上面的示例,可以使用小括号来获取更多匹配文本的信息。例如,直接利用小括号传递单词的首字母,然后进行大小写转换处理:


var s=/'script language=/"javaScript/"type=/"text/javaScript/"/';

var f=function($1,$2,$3){

return$2.toUpperCase+$3;

}

var a=s.replace(/b(w)(w*)b/g,f);//Script Language=/"JavaScript/"Type=/"Text/JavaScript/"


在函数f中,第一个参数表示每次匹配的文本,第二个参数表示第一个小括号的子表达式所匹配的文本,即单词的首字母,第二个参数表示第二个小括号的子表达式所匹配的文本。

实际上,replace方法的第二个参数(函数式参数)不需要传递任何形参,replace方法依然会向它传递多个实参,这些实参都包含一定的意思,具体说明如下:

❑第一个参数表示与匹配模式相匹配的文本,如上面示例中每次匹配的单词字符串。

❑其后的参数是与匹配模式中子表达式相匹配的字符串,参数个数不限,根据子表达式数而定。

❑后面的参数是一个整数,表示匹配文本在字符串中的下标位置。

❑最后一个参数表示字符串自身。

例如,将上面示例中替换文本函数改为如下形式。


var f=function{

return arguments[1].toUpperCase+arguments[2];

}


如果不为函数传递形参,直接调用函数的arguments属性,同样能够读取到正则表达式中相关匹配文本的信息。

❑arguments[0]表示每次匹配的单词。

❑arguments[1]表示第一个子表达式匹配的文本,即单词的首字母。

❑arguments[2]表示第二个子表达式匹配的文本,即单词的余下字母。

❑arguments[3]表示匹配文本的下标位置,如第一个匹配单词“script”的下标位置就是0,依此类推。

❑arguments[4]表示要执行匹配的字符串,这里表示“script language=/"javascript/"type=/"text/javascript/"”。


var s=/'script language=/"javascript/"type=/"text/javascript/"/';

var f=function{

for(var i=0;i<arguments.length;i++){

alert(/"第/"+(i+1)+/"个参数的值:/"+arguments[i]);

}

}

var a=s.replace(/b(w)(w*)b/g,f);


在函数体中,使用for循环结构遍历argumnets属性,每次匹配单词时,都会弹出5次提示信息,分别显示上面所列的匹配文本信息。其中,arguments[1]、arguments[2]会根据每次匹配文本不同,分别显示当前匹配文本中子表达式匹配的信息,arguments[3]显示当前匹配单词的下标位置。而arguments[0]总是显示每次匹配的单词,arguments[4]总是显示被操作的字符串。

例如,下面代码能够自动提取字符串中的分数,进行汇总后算出平均分,然后利用replace方法提取每个分值,与平均分进行比较以决定替换文本的具体信息。


var s=/"张三56分,李四74分,王五92分,赵六84分/";

var a=s.match(/d+/g),sum=0;

for(var i=0;i<a.length;i++){

sum+=parseFloat(a[i]);

};

var avg=sum/a.length;

function f{

var n=parseFloat(arguments[1]);

return n+/"分/"+/"(/"+((n>avg)?(/"超出平均分/"+(n-avg)):(/"低于平均分/"+(avg-n)))+/"分)/";

}

var s1=s.replace(/(d+)分/g,f);

alert(s1);/*/"张三56分(低于平均分20.5分),李四74分(低于平均分2.5分),王五92分(超出平均分15.5分),赵六84分(超出平均分7.5分)/"*/


在上面的示例中,遍历数组时不能够使用for in语句,因为这个数组中还存储着其他相关的匹配文本信息。应该使用for结构来实现。由于截取的数字都是字符串类型,所以应该把它们都转换为数值类型,否则会被误解,如把数字连接在一起,或者按字母顺序进行比较等。