JavaScript 网页编程从入门到精通 (清华社"视频大讲堂"大系·网络开发视频大讲堂)
上QQ阅读APP看书,第一时间看更新

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倍左右。如果操作的字符串巨大的话,通过数组中转来进行连接,则执行效率是非常明显的。当然,由于定义数组也会占用系统资源,使用完毕应该立即清除数组。所以,对于比较少的字符串连接操作来说,可以直接使用加号运算符来进行操作,当操作的字符串非常大时,可以考虑使用数组。