1. 程式人生 > >javascript語句——條件語句、迴圈語句和跳轉語句

javascript語句——條件語句、迴圈語句和跳轉語句

前面的話

  預設情況下,javascript直譯器依照語句的編寫順序依次執行。而javascript中的很多語句可以改變語句的預設執行順序。本文介紹可以改變語句預設執行順序的條件語句、迴圈語句和跳轉語句

條件語句

  指令碼的威力體現在它們可以根據人們給出的各種條件做出決策,javascript使用條件語句來做判斷

  條件語句(conditianal statement)通過判斷表示式的值來決定執行還是跳過某些語句,包括if語句和switch語句

【if語句】

  最常見的條件語句是if語句。if語句的條件必須放在if後面的圓括號內,條件的求值結果永遠是一個布林值,即只能是true或false。花括號中的語句,不管它們有多少條,只有在給定條件的求值結果是true的情況下才會執行

if(expression){
    statements;
}

  [注意]if語句中,括住expression的圓括號在語法上是必需的

  實際上,if語句中的花括號不是必不可少的。如果if語句中的花括號部分只包含一條語句,可以不使用花括號。但因為花括號可以提高指令碼的可讀性,所以在if語句中總是使用花括號是個好習慣

//可行,但不推薦
if(1>2)alert('1');

//推薦寫法
if(1>2){
    alert('1');
}

  if語句根據表示式的值改變程式流程。當expression的值為true時執行跟在其後的程式碼塊,當expression的值為false時,執行else的邏輯

if(expression)
    statement1
else
    statement2

  當在if/else語句中巢狀使用if語句時,必須注意確保else語句匹配正確的if語句

//錯誤暗示
if( i == j) if(j == k) console.log('i == k'); else console.log('i != j');

  javascript中的if/else匹配規則是:else總是和就近的if語句匹配

//實際解釋
if( i == j){
    if(j == k)
        console.log(
'i == k'); else console.log('i != j');//錯誤 }
//使用花括號
if(i == j){
    if(j == k){
        console.log('i == k');
    }
}else{
    console.log('i != j');
}

  當代碼有多條分支時,需要使用else if語句。else if語句並不是真正的javascript語句,它是多條if/else語句連在一起時的一種慣用寫法 

if(n == 1){
    //程式碼1
}else if(n == 2){
    //程式碼2
}else if(n == 3){
    //程式碼3
}else{
    //其他程式碼
}

  可以用if語句的巢狀形式來完成在語法上等價的程式碼,但沒有else if語句清晰

if(n == 1){
    //程式碼1
}else{
    if(n == 2){
        //程式碼2
    }else{
        if(n == 3){
            //程式碼3
        }else{
           //其他程式碼
        }
    }
}

【switch語句】

  當所有的分支都依賴於同一個表示式的值時,else if並不是最佳解決方案。在這種情況下,重複計算多條if語句中的條件表示式是非常浪費的做法,而switch語句正適合處理這種情況

  switch語句執行一個多路分支,首先計算expression的值,然後查詢case子句的表示式是否和expression的值相同。如果找到匹配的case,那麼將會執行這個case對應的程式碼塊。如果找不到匹配的case,那麼將會執行default標籤中的程式碼塊。如果沒有default標籤,switch語句將跳過它的所有程式碼塊

switch (expression)
  case value1: statement1;
    break;
  case value2: statement2;
    break;
  case value3: statement3;
    break;
  default: statement4;
if(n == 1){
    //程式碼1
}else if(n == 2){
    //程式碼2
}else if(n == 3){
    //程式碼3
}else{
    //其他程式碼
}
//等價於
switch(n){
    case 1:
        //程式碼1
        break;
    case 2:
        //程式碼2
        break;
    case 3:
        //程式碼3
        break;
    default:
        //程式碼4
}

  每一個case語句塊的結尾處都使用了關鍵字break。break語句可以使直譯器跳出switch語句或迴圈語句

  在switch語句中,case只是指明瞭要執行的程式碼起點,但並沒有指明終點。如果沒有break語句,那麼switch語句就會從與expression的值相匹配的case標籤處的程式碼塊開始執行,依次執行後續的語句,一直到整個switch程式碼塊的結尾

//如果沒有break語句,若switch語句匹配1,則不僅執行程式碼1,也會執行程式碼2和程式碼3
switch(n){
    case 1:
        //程式碼1
    case 2:
        //程式碼2
    default:
        //程式碼3
}

  如果確實需要混合幾種情形,要在程式碼中添加註釋,說明是有意省略了break關鍵字

switch(i){
    //合併兩種情形
    case 25:
    case 35:
        console.log('25 or 35');
        break;
    case 45:
        console.log('45');
        break;
    default:
        console.log('other');
}

  如果在函式中使用switch語句,可以使用return來代替break,return和break都用於終止switch語句,也會防止一個case語句塊執行完後繼續執行下一個case語句塊

//函式中使用switch語句
function convert(x){
    switch(typeof x){
        case 'number':
            return x.toString(16);
        case 'string':
            return '"' + x + '"';
        default:
            return String(x);
    }
}

  雖然ECMAScript中的switch語句借鑑自其他語言,但這個語句也有自己的特色。可以在switch語句中使用任何資料型別(在很多其他語言中只能使用數值),而且每個case的值不一定是常量,可以是變數或表示式

var num = 25;
switch(true){
    case num < 0:
        console.log('less than 0.');
        break;
    case num >=0 && num <=10:
        console.log('between 0 and 10.');
        break;
    case num >10 && num <=20:
        console.log('between 10 and 20.');
        break;
    default:
        console.log('more than 20.');
}

  使用switch語句時,要注意以下幾點:

  【1】由於每次執行switch語句時,並不是所有的case表示式都能執行到,因此,應該避免使用帶有副作用的case表示式,比如函式呼叫表示式和賦值表示式,最安全的做法是在case表示式中使用常量表達式

  【2】default標籤一般都出現在switch的末尾,位於所有case標籤之後,當然這是最合理也是最常用的寫法,實際上,default標籤可以放置在switch語句內的任何地方

  【3】switch語句中,對每個case的匹配操作實際上是'==='恆等運算子比較,而不是'=='相等運算子比較,因此,表示式和case的匹配並不會做任何型別轉換

//由於1並不會轉換為'1',所以結果是3
var n = 1;
switch(n){
    case '1':
        console.log(1);
        break;
    case 2:
        console.log(2);
        break;
    default:
        console.log(3);
}

迴圈語句

  條件語句把javascript中的程式碼變成一條條的分支路徑,而迴圈語句(looping statement)就是程式路徑的一個迴路,可以讓一部分程式碼重複執行

  javascript有4種迴圈語句:while、do/while、for、for/in,它們的工作原理幾乎一樣:只要給定條件仍能得到滿足,包含在迴圈語句裡的程式碼就將重複地執行下去。一旦給定條件的求值結果不再是true,迴圈也就到此為止。其中最常用的迴圈就是對陣列元素的遍歷

【while語句】

  while語句屬於前測試迴圈語句,也就是說,在迴圈體內的程式碼被執行之前,就會對出口條件求值

while(expression){
  statement
}

  當表示式expression是真值時則迴圈執行statement,直到expression的值為假值為止;如果是假值,那麼程式將跳過迴圈

  [注意]使用while(true)會建立一個死迴圈

  大多數迴圈都會有一個像count這樣的計數器變數。儘管迴圈計數器常用i、j、k這樣的變數名,但如果想要讓程式碼可讀性更強,就應當使用更具語義的變數名

var count = 0;
while(count < 10){
    console.log(count);
    count++;
}

【do while語句】

  do while語句是後測試迴圈,即退出條件在執行迴圈內部的程式碼之後計算。這意味著在計算表示式之前,至少會執行迴圈主體一次

do{
    statement
}while(expression);

  do/while迴圈和普通的while迴圈有兩點語法方面不同:

  【1】do/while迴圈要求必須使用關鍵字do來標識迴圈的開始,用while來標識迴圈的結尾並進入迴圈條件判斷

  【2】do/while迴圈用分號結尾。如果while迴圈體使用花括號括起來,則while迴圈也不用使用分號做結尾

function printArray(a){
    var len = a.length,i=0;
    if(len == 0){
        console.log('empty');
    }else{
        do{
            console.log(a[i]);
        }while(++i<len);
    }
}

【for語句】

  for語句提供了一種比while語句更加方便的迴圈控制結構,用for迴圈來重複執行一些程式碼的好處是迴圈控制結構更加清晰

  大部分的迴圈都具有特定的計數器變數,計數器的三個關鍵操作是初始化、檢測和更新。for語句將這三步明確宣告為迴圈語法的一部分,各自使用一個表示式來表示

for(initialize;test;increment){
    statement;    
}
//等價於:
initialize;
while(test){
    statement
    increment;
}

  [注意]使用continue語句時,while迴圈和for迴圈並不等價

  initialize、test和increment三個表示式之間用分號分隔,它們分別負責初始化操作、迴圈條件判斷和計數器變數的更新。將它們放在迴圈的第一行會更容易理解for迴圈正在做什麼,而且也可以防止忘記初始化或者遞增計數器變數

  initialize表示式只在迴圈開始之前執行一次;每次迴圈執行之前會執行test表示式,並判斷表示式的結果來決定是否執行迴圈體,如果test計算結果為真值,則執行迴圈體中的statement,最後,執行increment表示式

  在for迴圈的變數初始化表示式中,也可以不使用var關鍵字,該變數的初始化可以在外部執行

var count = 10;
var i;
for(i = 0; i < count; i++){
    console.log(i);
}

  由於ECMAScript中不存在塊級作用域,因此在迴圈內部定義的變數也可以在外部訪問到

var count = 10;
for(var i = 0; i < count; i++){
    console.log(i);
}
console.log(i);//10

for迴圈常見用途是對某個數組裡的全體元素進行遍歷處理

var beatles = Array('John','Paul','George','Ringo');
for(var count = 0; count < beatles.length; count++){
    alert(beatles[count]);
}

  如果迴圈中的一次迭代會改變多個變數,則需要用到逗號運算子,它將初始化表示式和自增表示式合併入一個表示式中以用於for迴圈

var i,j;
for(i = 0,j =10; i<10; i++,j--) sum+= i*j;

  程式碼中的迴圈變數除了是數字外,也可以是其他型別

  可以使用for迴圈來遍歷連結串列資料結構,並返回連結串列中的最後一個物件(也就是第一個不包含next屬性的物件)

function tail(o){
    for(;o.next;o = o.next)/*empty*/;
    return o;
}

  for迴圈中的initialize、test和increment這三個表示式中的任何一個都可以忽略,但是兩個分號必不可少。如果省略test表示式,那麼這將是一個死迴圈。同樣,和while(true)類似,死迴圈的另外一種寫法是

for(;;)

【for in語句】

  for/in語句也使用for關鍵字,但它和常規的for迴圈是完全不同的一類迴圈

for(variable in object){
    statement
}

  variable通常是一個變數名,也可以是一個可以產生左值的表示式或一個通過var語句宣告的變數,總之必須是一個適用於賦值表示式左側的值。object是一個表示式,這個表示式的計算結果是一個物件。同樣,statement是一個語句或語句塊,它構成了迴圈的主體

  for/in迴圈可以用來更方便地遍歷物件屬性成員

for(var p in o){
    console.log(o[p]);
}

  在執行for/in語句的過程中,javascript直譯器首先計算object表示式。如果表示式為null或undefined。javascript直譯器將會跳過迴圈並執行後續的程式碼。如果表示式等於一個原始值,這個原始值將會轉換為與之對應的包裝物件(wrapper object)。否則,expression本身已經是物件了。javascript會依次列舉物件的屬性來執行迴圈。然而,在每次迴圈前,javascript都會先計算variable表示式的值,並將屬性名(一個字串)賦值給它

  [注意]只要for/in迴圈中variable的值可以當做賦值表示式的左值,它可以是任意表達式,每次迴圈都會計算這個表示式,也就是說每次迴圈它計算的值有可能不同

var obj = {
  x: 1,
  y: 2
};
var props = [];
var i = 0;
for (props[i++] in obj);
props // ['x', 'y']

  javascript陣列不過是一種特殊的物件,因此,for/in迴圈可以像列舉物件屬性一樣列舉陣列索引

var o = {a: 1, b: 2, c: 3};
for (var i in o) {
  console.log(o[i]);
}
// 1
// 2
// 3

  [注意]for/in迴圈並不會遍歷物件的所有屬性,只有可列舉(enumerable)的屬性才會遍歷到

  ECMAScript規範並沒有指定for/in迴圈按照何種順序來列舉物件屬性。但實際上,主流瀏覽器廠商的javascript實現是按照屬性定義的先後順序來列舉簡單物件的屬性,先定義的屬性先列舉。如果使用物件直接量的形式建立物件,則將按照直接量中屬性的出現順序列舉。有一些網站和javascript庫是依賴於這種列舉順序的,瀏覽器廠商不大可能會修改這個順序

跳轉語句

  跳轉語句(jump statement)可以讓直譯器跳轉到程式的其他部分繼續執行,包括break、continue和return語句

【label語句】

  介紹跳轉語句不得不提到標籤(label)語句,通過給語句定義標籤,就可以在程式的任何地方通過標籤名引用這條語句

  標籤語句通常與break語句和continue語句配合使用,跳出特定的迴圈

identifier: statement

  [注意]用做標籤的identifier必須是一個合法的javascript識別符號,而不能是一個保留字

mainloop: while(token != null){
    //Todo
    continue mainloop;
}

  標籤的名稱空間和變數或函式的名稱空間是不同的,因此可以使用同一個識別符號作為語句標籤和作為變數名或函式名

  語句標籤只有在它所起作用的語句(當然也可以在它的子句中)內是有定義的。一個語句標籤不能和它內部的語句標籤重名,但在兩個程式碼段不相互巢狀的情況下,是可以出現同名的語句標籤的。帶有標籤的語句還可以帶有標籤,也就是說,任何語句可以有很多個標籤

【break語句】

  單獨使用break語句的作用是立即退出最內層的迴圈或switch語句

break;
for(var i = 0; i < a.length; i++){
    if(a[i] == target) break;
}

  break語句只有出現在迴圈語句或switch語句中才合法,出現在其他語句中會報錯

//報錯
if(true){
    break;
}
//報錯
function test(){
    var i = 0;
    break;
}
test();

  當希望通過break來跳出非就近的迴圈體或switch語句時,就會用到帶標籤的break語句

break labelname;

  當break和標籤一塊使用時,程式將跳轉到這個標籤所標識的語句塊的結束,或者直接終止這個閉合語句塊的執行。當沒有任何閉合語句塊指定了break所用的標籤,這時會產生一個語法錯誤

top:
  for (var i = 0; i < 3; i++){
    for (var j = 0; j < 3; j++){
      if (i === 1 && j === 1) break top;
      console.log( i, j);
    }
  }

  [注意]不管break語句帶不帶標籤,它的控制權都無法越過函式的邊界。比如,對於一條帶標籤的函式定義語句來說,不能從函式內部通過這個標籤來跳轉到函式外部

【continue語句】

  continue語句和break語句非常類似,但它不是退出迴圈,而是轉而執行下一次迴圈

continue;
continue labelname;

  不管continue語句帶不帶標籤,它只能在迴圈體內使用。在其他地方使用將會報語法錯誤

  當執行到continue語句時,當前的迴圈邏輯就終止了,隨即執行下一次迴圈。但在不同型別的迴圈中,continue行為也有所不同:

  【1】while迴圈中,迴圈開始處指定的exression會重複檢測,如果檢測結果為true,則迴圈體會從頭開始執行

  【2】do while迴圈中,程式執行直接跳到迴圈結尾處,這時會重新判斷迴圈條件,之後才會繼續下一次迴圈

  【3】for迴圈中,首先計算自增表示式,然後再次檢測test表示式,用以判斷是否執行迴圈體

  【4】在for/in迴圈中,迴圈開始遍歷下一個屬性名,這個屬性名賦給了指定的變數

  [注意]continue語句在while和for迴圈中的區別:while迴圈直接進入下一輪的迴圈條件判斷,但for迴圈首先計算其increment表示式,然後判斷迴圈條件

//1 3
for(i = 0; i < 5; i++){
    if(i % 2 === 0)continue;
    console.log(i);
}
//1 3 5 var i = 0; while(i<5){ i++; if(i % 2 === 0)continue; console.log(i); }

  由於continue在這兩種迴圈中的行為表現不同,因此使用while迴圈不可能完美地模擬等價的for迴圈

  和break語句類似,帶標籤的continue語句可以用在巢狀的迴圈中,用以跳出多層巢狀的迴圈體邏輯

top:
  for (var i = 0; i < 3; i++){
    for (var j = 0; j < 3; j++){
      if (i === 1 && j === 1) continue top;
      console.log('i=' + i + ', j=' + j);
    }
  }

【return語句】

  函式呼叫是一種表示式,而所有表示式都有值。函式中的return語句就是指定函式呼叫後的返回值

return expression;

  return語句只能出現在函式體內,如果不是會報語法錯誤。當執行到return語句時,函式終止執行,並返回expression的值給呼叫程式

function square(x)
{    
    return x*x
};
square(2);

  如果沒有return語句,則函式呼叫僅僅依次執行函式體內的每一條語句直到函式結束,最後返回呼叫程式。這種情況下,呼叫表示式的結果是undefined。return語句經常作為函式內的最後一條語句出現,但並不是說一定要放在函式最後,即使在執行return語句的時候還有很多後續程式碼沒有執行到,這時函式也還是會返回呼叫程式

  return語句可以單獨使用而不必帶有expression,這樣的話也會向呼叫程式返回undefined

function display_object(o){
    if(!o) return;
}

  在javascript詞法結構中,已經提到過分號的用法。所有的跳轉語句包括break、continue、return等語句,都不可以在關鍵字和表示式之間換行,因為javascript會在換行處填補分號

//以及return語句舉例,break、continue語句也類似
return
true;

  javascript將其解析為:

return;true;

  而程式碼的本意是:

return true;

參考資料