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

6.5 结构跳转

结构跳转语句主要包括标签、break、continue,它们常与条件语句、循环语句配合使用,来控制条件和循环流程,以提升代码运行效率。

6.5.1 标签语句

在JavaScript中,任何语句都可以添加一个标签,以便在复杂结构中设置程序跳转路径。定义标签语句的语法格式如下:

      label : statements

label为任意合法的标识符,但不能使用保留字。由于标签名与变量名属于不同的语法体系,所以不用担心标签名与变量名重叠。然后使用冒号分隔标签名与标签语句。

【示例】在下面代码中,b就是标签名,而a就是对象的属性名,其中标签b就是对对象结构进行标记。

      b:{
          a:true
      }

由于标签名和属性名都属于标签范畴,不能重名,下面这种写法是错误的:

      a:{                                         //标签语句的标记名
          a:true                                  //对象属性的标记名
      }

对象属性的标识名可以访问属性:

      var o={
          a:true
      }
      alert(o.a);                                  //通过对象成员标识符可以用对象成员

但是用户不能使用标签语句的标记名来引用被标记的语句,下面这种写法是错误的:

      b:{
          a:true
      }
      alert(b.a);                                  //不能够使用标签语句的标记名来引用被标记的语句

标签语句常用在循环结构中,以从嵌套循环中跳出。由于标签语句必须与其他跳转语句配合使用,在下面小节中再介绍标签语句的应用。

6.5.2 break语句

break语句能够终止循环或多重分支结构的执行。主要用在循环结构和switch多重分支结构中,用在其他地方都是非法的。

break语句独立成句,用法如下:

      break;

【示例1】break语句可以在循环结构中使用,用来退出循环结构。

      for(var i = 0; ; i++)
      {
          if(i>=10)break;                          //通过break语句来监测for循环操作
          alert(i);
      }

它等于:

      for(var i = 0; i < 10; i ++ )
      {
          alert(i);
      }

break关键字后面可以跟随一个标签名,用来指示程序终止执行之后要跳转的位置,并以该标签语句末尾的位置为起点继续执行。

      break label;

【示例2】在本示例中,设计了一个3层嵌套的循环结构。分别为每层循环定义一个标签,然后在内部通过条件结构来判断循环变量值的变化,并利用带有标签名的break语句进行跳转。

      a :for(var a = 0; a < 10; a ++ ){
          b :for(var b = 0; b < 10; b ++ ){
            c :for(var c = 0; c < 10; c ++ ){
                if(c == 1){
                    alert("c=" + c);
                    break c;
                }
                if(b == 1){
                    alert("b=" + b);
                    break b;
                }
                if(a == 1){
                    alert("a=" + a);
                    break c;
                }
            }
          }
      }

break语句和标签语句结合使用仅限于嵌套结构内部。

【示例3】在本示例中,设计3个并列的循环结构,企图在它们之间通过break语句和标签语句来实现相互跳转,这是不允许的。此时会提示编译错误,找不到指定的标签名。因为JavaScript在运行break语句时,仅限于当前结构或当前嵌套结构中寻找标签名。

      a :for(var a = 0; a < 10; a ++ ){
          if(a == 1){
              alert("a=" + a);
              break b;
          }
        }
        b :for(var b = 0; b < 10; b ++ ){
          if(b == 1){
              alert("b=" + b);
              break c;
          }
        }
        c :for(var c = 0; c < 10; c ++ ){
          if(c == 1){
              alert("c=" + c);
              break a;
          }
        }

使用带有标签的break语句时应注意以下两点。

只有使用嵌套的循环或者嵌套的switch结构,且需要退出非当前层结构时,才可以使用带有标签的break语句。

break关键字与标签名之间不能够包含换行符,否则JavaScript会把它们看作是两个句子,并分别单独执行。

break语句的主要功能是提前结束循环或多重分支判断。这在循环条件复杂,且无法预控制的情况下,可以避免死循环或者不必要的空循环。

【示例4】在本示例中,设计在客户端查找document对象的bgColor属性。如果完全遍历document对象,会浪费很多时间。在for/in结构中添加一个if结构判断所枚举的属性名是否等于“bgColor”,如果相等,则使用break语句跳出循环结构。

      for(i in document){
          if(i.toString() == "bgColor"){
            document.write("document." + i + "=" + document[i] + "<br />");
            break;
          }
      }

在上面代码中,break语句并非跳出当前的if结构体,而是跳出当前最内层的循环结构。

【示例5】在下面嵌套结构中,break语句不是退出for/in循环体,而是退出switch结构体。

      for(i in document){
          switch(i.toString()){
            case "bgColor":
                document.write("document." + i + "=" + document[i] + "<br />");
                break;
            default:
                document.write("没有找到");
          }
      }

【示例6】针对上面示例,如果需要退出外层的循环结构,就需要为for语句定义一个标签outloop,然后在break语句中指定该标签名,以便从最内层的多重分支结构中跳出最外层的for/in循环结构体。

      outloop:for(i in document){
          switch(i.toString()){
            case "bgColor":
                document.write("document." + i + "=" + document[i] + "<br />");
                break outloop;
            default:
                document.write("没有找到");
          }
      }

6.5.3 continue语句

continue语句与break语句都独立成句,用于循环结构,break语句用于停止循环,而continue语句用于停止当前循环,继续执行下一次循环。

与break语句语法相同,continue语句可以跟随一个标签名,用来指定继续执行的循环结构的起始位置:

      continue label;

【示例1】在本示例中,当循环变量等于4时,会停止循环体内最后一句的执行,返回for语句继续执行下一次迭代:

      for(var i=0; i<10; i++)
      {
          alert(i);
          if(i==4)continue;                         //继续执行下一次迭代
          alert(i);
      }

continue语句只能在循环结构(如while、do/while、for、for/in)内使用,在其他地方都会引发编译错误。当执行continue语句时,会停止当前迭代过程,开始执行下一次的迭代。但是对于不同的结构体,其继续执行的位置也略有不同。

对于for循环结构来说,将会返回执行for语句后第三个表达式,然后再执行第二个表达式,如果条件满足,则继续执行下一次迭代,如图6-4所示。

图6-4 continue语句在for结构中的执行路线图

对于for/in循环结构来说,将会以下一个赋给循环变量的属性名再次开始新的迭代。

对于while循环结构来说,将会返回再次检测while语句后的表达式,如果为true,则重新开始执行循环体内所有语句,如图6-5所示。

图6-5 continue语句在while结构中的执行路线图

【示例2】下面这个循环结构被执行时,将成为死循环。

      var i=0;
      while(i<10){
          alert(i);
          if (i==4) continue;
          i++
      }

对于do/while循环结构来说,会跳转到底部的while语句先检测条件表达式,如果条件为true,则将从do语句后开始下一次的迭代,如图6-6所示。

图6-6 continue语句在do/while结构中的执行路线图

do/while结构与while结构比较相似,其中continue语句下面的语句将被忽略掉。但是在JavaScript 1.2版本中存在一个Bug,它将不检测底部的while语句后的循环条件,而是直接跳转到顶部do语句后面开始下一次迭代。所以,在使用do/while结构时应该注意这个安全风险。

【示例3】在本示例中,利用continue语句辅助过滤掉数组a中的字符串元素:

      var a=[1, "d",2, "a", "b", "c",3,4]                    //定义并初始化数组a
      var b=[], j=0;                                         //定义数组b和变量j
      for(var i in a){                                       //遍历数组a
          if(typeof a[i] == "string")
            //如果元素数据类型为字符串,则返回继续下一次迭代
            continue;
          b[j++]=a[i];                                       //把非字符串类型的元素值赋值给数组b
      }
      alert(b);                                              //返回1,2,3,4