在javascript中,表達式是片語,那麼語句(statement)就是整句或指令。正如英文語句以句號結尾,javascript以分號結尾。
表達式計算出一個值,但語句使某件事發生。
「使某件事發生」的一個方法是計算帶有副作用的表達式。諸如賦值和函數呼叫這些有副作用的表達式,是可以作為單獨的語句的。這種把表達式當做語句的用法也稱為做表達式語句(expression statement)。類似的語句也有宣告語句(declaration statement),宣告語句用來宣告新變數或定義新函數。
javascript程式就是一系列的可執行語句的集合,預設情況下,javascript解釋器依照編寫順序依序執行。另一種「使某件事情」發生的方法就是改變語句的預設執行順序:
1.條件語句(conditional)語句:javascript解釋器可以根據一個表達式的值來判斷;來執行或跳過這些語句,例如if和switch語句。
2.迴圈語句(loop)語句:可以重複執行的語句,例如while和for語句
3.跳轉(jump)語句:可以讓解釋器跳轉至程式的其它部分繼續執行、例如break、return和throw語句
接下來本文將介紹javascript中各式各樣的語句和其語法。本章最後對這些語句做了總結。一個javascript程式只不過是以分隔分割的語句集合,所以一旦掌握了javascript語句,就可以寫javascript程式了。
1.表達式語句
賦值語句是一種比較重要的表達式語句,它的作用就是改變一個變數的值,就像執行一條賦值語句一樣:例如
greet = "hello" name;
i *= 3;
遞增運算子( )和遞減運算子(--)和賦值語句有關。它們的作用是改變一個變數的值,就像執行一條賦值語句一樣。
counter ;
delete運算子的重要作用就是刪除一個物件的屬性(或陣列的元素),所有它一般都作為語句使用,而不是作為複雜表達式的一部分。
delete o.x;
函數呼叫是表達式語句的另一個大類,例如
alert(greet);
window.close();
雖然這些客戶端函數都是表達式,但它們對web瀏覽器造成了一定的影響。所以我們認為也是語句,呼叫一個沒有副作用的函數是沒有意義的,除非它是複雜的表達式或賦值語句的一部分,例如。不可能隨便把一個餘弦值丟棄;
Math.cos(x);
相反,得出餘弦值就得把它賦值給一個變量,以便將來使用這個值:
var cx = Math.cos(x);
再次提醒各位,每行程式碼就是以分號結束的。
2.複合語句與空語句
可以用逗號運算子將幾個表達式連接在一起,形成一個表達式。同樣,javascript也可以講多條語句結合在一起,形成一個複合語句(compound statement)。只要花括號將多條語句括起來即可。因此,下面幾行程式碼可以當成一條單獨的語句,使用在javascript任何希望使用一條語句的地方。
{
x = Math.PI;
cx = Math.cos(x);
console.log("cos(π)=" cx);
}
關於語句區塊有幾點要注意:第一,語句區塊不需要分號。區塊中的元素語句必須以分號結尾,但語句區塊不需要。
第二,語句區塊中的行都有縮進,這不是必須的,但整齊的縮排能使程式碼可讀性更強,更容易理解。
第三,javascript沒有區塊級作用域,在語句區塊中宣告的變數並不是語句塊所私有的。 (參考3章10節第一小節)
將很多條語句合併成一個大語句塊的做法在javascript程式設計中非常常見。類似的表達式通常包含子表達式一樣,很多javascript包含其它子語句,從形式來講,javascript通常允許一個語句塊包含一條子語句。例如:while迴圈的迴圈體就可以只包含一條語句。使用語句塊,可以將任意數量的語句放到這個區塊中,這個語句塊可以當作一條語句來使用。
在javascript中,當希望多條語句被當做一條語句使用時,使用符合語句來取代。空語句(empty statement)則剛好相反,它允許包含0條語句。空語句如下圖所示:
;//分號
javascript解釋器在執行空語句時顯然不執行任何動作,但實踐證明:當創建一個具有空循環體的循環時,空語句有時是很有用的,例如下面的for循環
//初始化一個陣列a
for (i = 0; i
在這個循環中,所有的操作都在表達式a[i ]=0中完成,這裡並不需要任何循環體。然而javascript需要在循環體中至少包含一條語句,因此這裡只使用了一個單獨的分號來表示一條空語句。
注意,在for迴圈、while迴圈或if語句的右邊園括號的分號很不起眼,這很可能造成 一些致命的bug,而這些bug很難定位到。例如下面的程式碼的執行結果很可能就是作者不想要的效果:
if((a==0)||(b==0)); //這行程式碼什麼也沒做....
o = null; //此行程式碼總是執行
如果有特殊目的使用空語句,最好在程式碼中加入註釋,這樣能更清楚的說明這條空語句是有用的
for (i = 0; i
3.宣告語句
var和function都是宣告語句,它們宣告或定義變數或函數。這些語句定義標識符(變數名和函數名)並給其賦值,這些標識符可以在程式任意地方使用。宣告語句本身什麼也不做,但它有一個重要意義:透過建立變數和函數,可以更好的組織程式碼的語意。
接下幾節將講述var語句和function語句,但不包含變數和函數的全部內容。
i.var
var語句用來宣告一個或多個變量,它的語法如下:
var name_1[ = value_1][, ..., name_n[ = value_n]]
關鍵字var之後跟隨的是要宣告的變數列表,列表中的每一個變數都可以帶有初始化表達式,可用來指定它的初始值。例如:
var i; //一個簡單的變項
var j = 0; //一個有初始值的變數
var p, q; //兩個變數
var greet = "hello" name; //更複雜的初始化表達式
var x = 2.34,y = Math.cos(0.75),r, theta; //很多變數
var x = 2,y = x * x; //第二個變數使用了第一個變數
var x = 2,
f = function(x) {return x * x}, //各變項獨佔一行
y = f(x)
如果var語句出現在函數體內,那麼定義的是局部變量,其作用域就是這個函數。如果在頂層程式碼中使用var語句,那麼它宣告的是全域變量,在整個javascript中,都是可見的。在第三章10節提到:全域變數是全域物件的屬性,然後和其它全域物件屬性不同的是,var宣告的變數是無法透過delete刪除的。
如果var語句中的變數沒有指定初始化表達式,那麼這個變數的值初始為undefined。所以,在宣告語句之前的變數值就是undefined。
要注意的是,var語句同樣可以作為for迴圈或for/in迴圈的組成部分。 (在循環之前宣告的變數宣告一樣,這裡宣告變數也會"提前"),例如:
for (var i = 0; i for (var i = 0, j = 10; i for (var i in o)console.log(i);
注意,多次聲明同一變數是無所謂的。
ii.function
關鍵字function用來宣告函數的,我們已經學過函數表達式(4.3).函數定義可以寫成語句的形式。例如:下面範例程式碼中的兩種定義寫法:
var f = function f(x) {return x 1;} //將表達式賦值給一個變數
function f(x){return x 1;} //含變項名稱的語句
函數宣告的語法如下:
function funcname([arg1[, arg2[..., argn]]]) {
statements
}
funcname是要宣告的函數的名稱識別碼。函數名稱之後是參數列表,參數之間使用逗號隔開。當呼叫函數的時候,這些標識符則指涉傳入函數的實參。
函數體是由javascript語句組成的,語句數量不限,且用花括號括起來。在定義函數時,並不會執行函數體內的語句,它和呼叫函數時待執行的新函數物件相關聯。請注意,function函數語句裡的花括號是必須的,這和while迴圈和其它一些語句鎖使用的語句塊是不同的,即使函數體只有一條語句,仍然需要花括號將其括起來。
function hyteus(x, y) {
return Math.sqrt(x * x y * y);
}
hyteus(1, 2) //=>2.23606797749979
function facial(n) { //一個遞歸函數
if (n return n * facial(n - 1);
}
facial(11) //=>39916800
函數的宣告通常出現在javascript程式碼的最頂部,也可以嵌套在其他函數體內。但在巢狀時,函數宣告只能出現在所嵌套的函數頂端。也就是說:函數定義不能出現在if、while、或其他語句中。
和var語句一樣,函數宣告語句所建立的變數也是不可刪除的。但是這些變數不是唯讀的,變數值可以重寫。
4.條件語句
條件語句是透過判斷指定的表達式的值是否來執行或跳過某些語句。這些語句是代碼的”決策點“,有時稱為”分支“。如果javascript解釋器是按照程式碼的」路徑「執行的。條件語句就是這條路上的分岔點。程式到達這裡必須選擇一條路徑來繼續執行。
i.if語句
if語句是基本的控制語句,準確的說,它讓程式有條件的執行,這種語句有兩種形式:第一種是
if (expression)
statement
這種形式中,判斷expression 的值,如果是真,執行statement語句,如果是假值,就不執行statement.例如
if (username == null) //若username是null或undefined
username = "jack wong"; //定義
要注意的是,if語句括住expression的園括號是必須的。
javascript語法規定,if關鍵字和帶園括號的表達式之後必須跟隨一條語句。但可以使用語句區塊將多條語句合成一條。因此,if語句的形式如下所示:
if (!address) {
address = "";
message = "please mailing address"
}
if語句的第二種形式引入了else子句,當expression的值是false值時執行else 邏輯
if (expression)
statement1
else
statement2
例如以下程式碼
if (n == 1)
console.log("1 new message");
else
console.log("you have" n "new message");
當if/else語句中,嵌套使用if語句時,必須注意確保else語句符合正確的if語句。考慮以下程式碼:
i = j = 1;
k = 2;
if (i == j)
if (j == k)
console.log("i equs k");
else
console.log("i dosent equal j"); //錯誤! !
這個實例中,內層的if語句構成了外層if語句所需要的子句。但是,if和else的匹配關係不清晰(只有縮排給了一點暗示)而且在這個例子裡,縮排給出的暗示是錯誤的,因為javascript解釋器是這麼理解的。
if (i == j) {
if (j == k)
console.log("i equs k");
else
console.log("i dosent equal j");
}
和大多程式語言一樣,javascript中的if、else匹配規則是,else總是和就近的if語句匹配,為了讓個例子的可讀性更強,更容易理解,更方便維護和調試,應使用花括號
if (i == j) {
if (j == k) {
console.log("i equs k");
} else { //花括號使程式碼的結果更清楚
console.log("i dosent equal j");
}
}
許多程式設計師都將有if和else語句主體用花括號括起來的習慣(就像類似while循環這樣的符合語句中一樣),即使每條分支只有一條語句,但這樣做能避免剛才的程序歧義問題。
ii.else if
if/else語句透過判斷一個表達式的計算結果來選擇兩個分支中的一個。當程式碼中有許多條分支的時候該怎麼辦呢?一個解決的辦法是使用else if語句。 else if並不是真正的javascript語句,它只不過是多條if / else語句連結在一起的寫法。
if (n == 1) {
//執行碼區塊 1
} else if (n == 2) {
//執行碼區塊2
} else if (n == 3) {
//執行碼區塊3
} else {
//先前的條件為false,而執行代碼區塊4
}
這種程式碼沒有什麼特別之處,它由多個if語句組成,每個if語句的else的子句又包含另外一條if語句。可以用if語句的嵌套形式來完成語法上的等價代碼,但與此相比,顯然else if的寫法更加清晰也更可取。
iii.switch
if語句在程式執行的過程中,建立一支分支,並且可以使用else if來處理多個分支。然後,當所有的分支都依賴同一個表達式的值時,else if並不是最佳的解決方案。在這種情況下,重複計算多條if語句中的表達式是非常浪費的做法。
switch語句適合處理這種情況。關鍵字switch之後緊跟著園括號括起來的一個表達式。隨後是花括號括起來的程式碼區塊。
switch (expression) {
statements
}
然而switch語句完整的語法比這更複雜一些。 case之後是一個表達式和冒號,case和標記語很類似,只是這個標記語並沒有名字。
它只和他後面的表達式關聯在一起。當執行這條switch語句時,它會先計算expression的值,然後再找出case子句的表達式是否和expression的值相同。 (這裡的相同是按照“===”運算符進行比較的),如果匹配case,它將執行對應的程式碼。如果找不到符合的case,它將會執行"default:"標籤中的程式碼區塊。如果沒有「default:」標籤,switch將跳過所有的程式碼區塊。
switch語句是非常容易混淆的,用例子介紹會比較清晰一點,下面的switch語句和方才的if/else語句是等價的
switch (n) {
case 1: //若n ===1從這裡開始
//執行碼區塊1
break;
case 2:
//以2
break;
case 3:
//執行碼區塊3
break;
default:
//執行碼區塊4
break;
}
要注意的是,每個case語句的結尾都使用了關鍵字break。我們將後面介紹break語句,break語句可以使解釋器跳出switch語句或循環語句。在switch中,case只是指明了要執行的程式碼起點,但沒有指明終點。如果沒有break語句,那麼switch語句就從expression的值的匹配的case標籤處程式碼開始執行,依序執行後續的語句,一直到整個switch程式碼區塊結束。當然,如果在函式中使用switch語句,可以使用return來取代break,return和break都用來終止switch語句,也會防止一個case語句執行完繼續執行下一個case語句區塊。
下面的語句貼近實戰,它會根據值的型別將該值轉換為字串。
function convert(x) {
switch (typeof x) {
case 'number': //數位轉換為16進位
return x.toString(16);
case 'string':
return '"' x '"'; //傳回兩段雙引號的字串。
default: //使用一般方法轉換其它類型
return String(x);
}
}
console.log(convert(100255114)) //=>5f9c58a
注意,在上面的兩個例子中,case關鍵字後跟隨的是數字和字串直接量,在實際中這是switch最常見的用法,但是ECMAScript標準允許每個關鍵字跟隨任意的表達式。
switch語句先計算switch 關鍵字後的表達式,然後按照從上到下的順序計算每個case後的表達式,知道執行到case的表達式的值和switch的表達式的值相等時為止。由於對每個case的匹配操作實際上是“===”恆等運算符比較,而不是“==”,因此表達式和case的匹配並不會做任何類型轉換。
每次執行switch語句的時候,並不是所有的case表達式都能執行到,因此,應避免帶有副作用的case表達式,例如函數呼叫的表達式和賦值表達式。最安全的做法就是在case表達式中使用常數表達式。
前面提到過,switch表達式與所有的case表達式都不匹配,則執行標記為「default:」的語句區塊,如果沒有"default:"標籤,則switch整個語句都跳過。在先前的範例中,「default:」標籤都出現在switch末尾,位於所有case標籤之後,當然這是最合理也是最常用的寫法。實際上,「default:」標籤可以放在switch語句內任何地方。
5.循環。
為了理解條件語句,可以將javascript中的程式碼想成一條條分支路徑。迴圈語句(looping statement)就是程式路徑的一個迴路,可以讓一部分程式碼重複執行。 javascript中有四種循環語句:while、do/while、for、for/in下面幾節會一次講解他們。其中最常用的循環就是數組元素的遍歷,(7.6會詳細討論這個循環和使用數組類別定義的特殊循環方法。)
i.while
if語句是一種基本的控制語句,用來選擇執行程式的分支語句。和if一樣,while語句也是一個基本的迴圈語句,它的語法如下:
while (expression)
statement
在執行while語句之前,javascript解釋器首先計算expression的值,如果它的值是假值,那麼程式將跳過迴圈體中的邏輯statement轉而執行程式中的下一語句。如果它的值是真值,則執行循環體statement內的邏輯,然後再計算表達式expression的值,種循環會持續下去,知道expression的值為假值為止。換個說法 就是表達式為expression是真值的時候則循環執行statement,注意,使用while(true)則會建立一個死循環。
通常來說,我們不想讓javascript重複執行相同操作。在幾乎每一次循環中,都會有一個或多個變數隨著循環而迭代改變。正是由於改變了變數這些變量,因此每次循環執行的statement的操作也不盡相同,而且,如果改變變量在expression中用到,那麼每次循環表達式的值也不同。這一點非常重要,負責初始值為真值的表達式永遠是真值,循環也不會結束,下面的這個範例所示while循環輸出0-9值。
var count = 0;
while (count console.log(count);
count ;
}
可以發現,在這個例子中,變數count的初始值為0,在循環的過程中,它的值每次都遞增1,當循環執行了十次。表達式的值就編程了false,這時while就會結束,javascript解釋器會執行程式下一語句。大多數循環都有一個像count這樣的計數器變數。雖然計數器常用i j k這樣的變數名,但如果想讓程式碼的可讀性更強,就應該使用更具體的語法名稱。
ii.do/while
do/while循環和while循環非常相似,只不過它是在循環的尾部而不是頂部檢測循環表達式,這意味著這循環體至少執行一次。 do/while循環的語法如下:
do
statement
while(expression);
do/while迴圈不像while迴圈那麼常用。這是因為在實務上想要循環至少執行一次的情況並不常見。下面是一個do/while循環的例子
function printArray(a) {
var len = a.length,
i = 0;
if (len == 0)
console.log("空白陣列");
else
do {
console.log(a[i]);
} while ( i
}
printArray([1,5,2,6])
在do/while循環和普通while循環之間有兩點語法方面的差異。首先,do循環要求必須使用關鍵字do來標識循環的開始,用while變標識循環的結尾並進入循環條件判斷;其次,和while循環不同,do循環使用分號結尾的。如果while的迴圈體使用花括號括起來,則while迴圈也不使用分號結尾。
iii.for
for語句提供了一個比while更方便的迴圈語句控制結構。 for語句對常用的迴圈模式做了一些簡化。大部分的循環都具有特定的計數器變數。在循環開始之前要初始化這個變量,然後在每次循環之前檢查下它的值。最後,計數器變數做自增操作,否則就在迴圈結束後、下次判斷前做修改。在這類循環中,計數器的三個關鍵操作是初始化、偵測和更新。 for語句就將這三部操作明確宣告為迴圈語法的一部分,各自使用一個表達式來表示。 for語句的語法如下:
for (initialize; test; increment)
statement
intialize、test、increment三個表達式之間使用分號分隔,他們負責初始化操作、循環條件判斷和計數器變數的更新。將它們放在迴圈的第一行會更容易理解for迴圈正在做什麼,而且也可防止忘記初始化或遞增計數器變數。
要解釋for循環是怎麼樣運作的,最簡單方法就是列出一個與之等價的while循環
initialize
while (test) {
statement
increment;
}
換句話說,initialize表達式只在迴圈 開始前執行一次。初始化表達式應具有副作用(通常是一條賦值語句)。 javascript同樣允許初始化表達式中帶有var變數宣告語句,這樣的話就可以宣告並初始化一個變數。每次迴圈前會執行test表達式,並判斷表達式的結果來決定是否執行迴圈體。每次迴圈前會執行test表達式,並判斷其結果是否來執行迴圈體,如果test結果為真值,則執行迴圈體中的statement。最後,執行increment表達式。同樣為了有用起見,這裡的increment表達式也必須有副作用。通常來講,它不是一個賦值表達式就是一個由「 」、「--」運算子構成的表達式。
上文的while迴圈可以使用for迴圈來從寫
for (var count = 0; count console.log(count)
當然,有些循環比較複雜,而且循環中一次迭代多個變數。在javascript,這種情況必須用到逗號運算符,它將初始化表達式和自增表達式合併入一個表達式中以用於for迴圈。
var i, j;
for (i = 0, j = 10; i console.log(i * j);
到目前為止,在範例程式碼中的循環變數都是數字。當然是數字是最常用的,但不是必須的。下面這段程式碼就使用for迴圈來遍歷資料結果,並回傳鍊錶中最後一個物件(也就是第一個不包含next屬性的物件)
function tail(o) { //返回鍊錶的最後一個節點物件
for (; o.next; o = o.next) /*empty*/ //依據判斷o.next是否為真值來執行遍歷
return o;
}
要注意的是,這段程式碼不包含initialize表達式,for迴圈中的那三個表達式中的人和一個都可以忽略,但兩個分號必不可少。如果省略test表達式,那麼將會是一個死循環。同樣和while(ture)類型,死循環的令一種寫法是for(;;)。
iiii.for/in
for/in語句使用for關鍵字,但它和常規的for迴圈是不同的一類迴圈。 for/in迴圈的語法如下
for (variable in object)
statement
variable通常是一個變數名,也可以是一個可以產生左值的表達式或一個透過var語句宣告的變數。總之是一個適用於賦值表達式左側的值。 object是一個表達式,這個表達式的計算結果是一個物件。同樣,statement是一個語句或語句區塊,它構成了一個迴圈的主體。
使用for迴圈來遍歷陣列元素是非常簡單的
var a = [1, 3, 5, "44"];
for (var i = 0; i console.log(a[i]) //輸出每個陣列的元素
而for/in迴圈則是用來方便的遍歷物件成員屬性
for (var p in o) //將屬性的名字賦值給變數p
console.log(o[p]); //輸出每一個屬性的值
在執行 for/in語句的過程中,javascript解釋器首先計算object表達式。如果表達式為null或undefined,javascript解釋器將跳過循環並執行後續的程式碼。如果表達式等於一個原始值,這個原始值將會轉換為與之對於的包裝物件(wapper object)(3.6節)。否則,expression本身已經是物件了。 javascript會依序列舉物件的屬性來執行循環。然而在每次循環之前,javascript都會計算variable表達式的值,並將屬性名稱(一個字串)賦值給它。
要注意的是,只要for/in循環中,varibale的值可以當做賦值表達式的左值,它可以是任意表達式。每次循環都會計算這個表達式,也就是說每次循環它計算的值可能不同。例如,可以使用下面的這段程式碼將所有物件屬性複製到一個陣列中:
var o = {x: 1,y: 2,z: 3};
var a = [],i = 0;
for (a[i ] in o) /*empty*/;
document.write(a)//=> x,y,z
javascript數組只不過是一種特殊的對象,因此,for/in循環可以像枚舉對象屬性一樣列舉資料索引。例如在上面的程式碼之後加入這段程式碼,就可以列舉資料索引0,1,2:
var o = {x: 1,y: 2,z: 3};
var a = [],i = 0;
for (a[i ] in o) /*empty*/;
document.write(a)//=> x,y,z將物件屬性複製到一個陣列中
for(i in a)
document.write(i) //=>枚舉資料索引 0 1 2
其實,for/in迴圈並不會遍歷物件的所有屬性,只有「可列舉」(enumerable)的屬性才會遍歷到(參考6.7)。由於javascript語言核心所定義的內建方法就不是「可列舉的」。例如,所有的物件都有toString(),但for/in迴圈並不會列舉toString()這個屬性。除了內建的方法之外,還有很多內建物件的屬性是不可枚舉的(nonenumberable)。而程式碼中定義的所有屬性和方法都是可枚舉的(6.7節會講到,但ECMAScript5中有特殊手段可以使屬性變成不可枚舉)。
物件可以繼承其它物件的屬性,那行繼承自訂屬性(6.2.ii)也可以使用for/in列舉出來。
如果for/in的迴圈體刪除了還未列舉的屬性,那麼這個屬性將不會再列舉。如果循環體定義了物件的 新屬性,這些屬性通常也不會列舉(不過。javascript有些實作可以列舉那麼些在循環體中增加的屬性)。
屬性枚舉的順序
ECMAScript規格並沒有指定for/in迴圈依照何種順序來列舉物件的屬性。但實際上,主流的瀏覽器廠商javascript實作是依照屬性定義的先後順序來列舉簡單物件的屬性,先定義的屬性先列舉。如果使用物件直接量的形式建立對象,則將依照直接量中屬性的出現順序列舉。 (有一些網子和javascript函式庫是依賴這種枚舉順序的,而瀏覽器廠商大多不修改這個順序),在下面的情況下,枚舉順序取決於具體的實作(並非互動)
1.物件繼承了可枚舉屬性
2.物件具有整數數組索引的屬性
3.使用delete刪除了物件已有的屬性
4.使用Object.defineProperty()或類似的方法改變了物件屬性
6.跳轉
javascript中令一類語句是跳躍語句(jump statement)。從語句理解,它可以使javascript執行從一個位置跳到令一個位置。
break語句是跳到迴圈或其他的語句結束。 continue語句是終止本次迴圈的執行並開始下一次迴圈的執行。 javascript中的語句可以命名或帶有標籤,break和continue可以標識目標迴圈或其它語句標籤。
return語句可以讓解釋器跳出函數體的執行。並提供本次呼叫的返回值。 throw語句觸發或拋出一個異常,它是與try/catch/finally語句一同使用的,這些語句指定了處理異常代碼邏輯。這是一種複雜的跳躍語句,當拋出一個異常的時候,程式會跳至最近的閉合異常辰星,這個異常程式可以是在同一個函數中或更高層的呼叫堆疊中。
接下來,描述每一種跳轉語句
i.標籤語句
語句是可以加上標籤的,標籤是由語句前的識別碼和冒號組成:
identifier:statement
透過為語句定義標籤,就可以在程式中任何地方透過標籤名稱來引用這條語句。可以對多條語句定義標籤,儘管只有在語句區塊定義標籤時才有更有用,例如循環語句或條件判斷語句。透過為迴圈定義一個標籤名,可以在迴圈體內部使用break和continue來退出迴圈或直接挑戰到下一個迴圈開始。 break和continue是javascript中唯一可使用語句標籤的語句(本章接下來會講述)。下面的例子,其中while循環定義了一個標籤,continue語句使用了這個標籤:
mainloop: while (token != null) {
//忽略這裡代碼...
continue mainloop; //跳到下一次迴圈
//忽略這裡的代碼...
}
這裡做標籤的indentifier必須是一個合法的javascript標識符,而不能是一個保留字。標籤的命名空間和變數或函數的命名空間是不同的,因此可以使用同一個識別碼作為語句標籤和作為變數名稱或函數名稱。語句標籤只在它所起作用的語句(當然可以在它的子句)內是有定義的。一個語句標籤不能和它內部的語句標籤重名,但在兩個程式碼不互相嵌套的情況下是可以出現同名語句標籤的。有標籤的語句也可以有標籤,也就是說,任何語句可以有許多個標籤。
ii.break
單獨使用break語句的作用是立即退出最記憶體的迴圈或switch語句。它的語法如下:
break;
由於它能夠使迴圈和switch語句退出,因此這種形式的break只能出現在這類語句中才是合法的。
我們在switch語句的例子中已經見到果break語句。在循環中,無論出於什麼原因,只要不想繼續執行整個循環,就可以用break提前退出。當迴圈終止條件非常複雜時,要函數體內使用break語句實現這樣些條件判斷的做法要比直接在迴圈表達式中寫出這個複雜的終止條件做法簡單的多。
下面的例子中循環遍歷整個數組元素來查找某個特定的值,當整個數組遍歷完成後正常退出循環,如果找到 了需要查找的數組元素,則使用break語句退出循環:
for (var i = 0; i if (a[i] == target) break;
}
javascript中同樣允許break關鍵字後面跟著一個語句標籤,(只有標識符,沒有冒號)
break labelname;
當break和標籤一塊使用時,程式會跳到這個標籤所辨識的語句區塊的結束,或直接終止這個閉合語句區塊的執行。當沒有任何閉合語句區塊指定break所用的標籤,這時會產生一個語法錯誤。當使用這種形式的break語句時,有標籤的語句不應該是迴圈或switch語句,因為break語句可以「跳出」任何閉合的語句塊。這裡的語句可以是由花括號組起來的一組語句,使用同一個標籤來辨識一組語句。
break關鍵字和labelname之間不能換行。因為javascript可以給語句自動補全省略掉的分號,如果break關鍵字和標籤之間有換行,javascript解釋器會認為你在使用break不帶標籤的最簡形式,因此會在break後面補充分號.
當你希望透過break來跳出非就近的迴圈體或switch語句時,就會用到有標籤的break語句。下面是範例程式碼:
var matrix = getData(); //從某處取得一個二維陣列
//將矩陣中所有元素求和
var sum = 0,
success = false;
//從簽章開始,以便在已錯誤時推出程式。
compure_sum: if (matrix) {
for (var x = 0; x var row = matrix[x];
if (!row) break compure_sum;
for (var y = 0; y var cell = row[y];
if (isNaN(cell)) break compure_sum;
sum = cell;
}
}
success = true;
}
//break語句跳至此
//如果success =false條件已到達這裡,表示我們給予的矩陣中有錯誤
//否則將矩陣中所有的元素求和
最後,要注意的是,不管break語句帶不帶標籤,它的控制權都無法越過函數的邊界。例如:對於一條帶有標籤的函數定義語句來說,不能透過函數內部透過這個標籤來跳到函數外部.
iii.continue語句
continue語句和break語句非常類似,但它不會退出循環,而是轉而執行下一次迴圈。 continue語句的語法和break的語句語法一樣簡單
continue;
continue語句會也會有標籤
continue lebname;
不管continue語句帶不帶標籤,它只能在循環體使用,在其它地方使用將會 報語法錯誤。
當執行到continue語句的時候,目前的循環邏輯就終止了,隨即執行下一次循環,在不同類型的循環中,continue的行為也有區別
1. 在while循環中,在循環開始處指定expression會重複檢測,如果檢測結果為true,循環體會從頭執行。
2. 在do/while循環中,程式的執行至今跳到迴圈的結尾處,這時會重新判斷循環條件,之後才會繼續下一次循環。
3. 在for循環中,首先會計算自增表達式,然後再偵測test表達式,用來判斷是否執行循環體。
4. 在for/in迴圈中,迴圈開始遍歷下一個屬性名,這個屬性名賦給了指定的變數。
需要注意continue語句在while和for迴圈的差別,while迴圈直接進入下一輪的迴圈條件判斷,但for迴圈先計算器increment表達式,然後判斷迴圈條件。先前的章節討論了和while循環「等價」的for循環行為。但由於continue在這兩個循環中行為表現不同,因此使用while循環不可能完美的模擬等價的for循環。
下面這段程式碼展示了沒有標籤的continue語句,產生一個錯誤的時候跳過目前迴圈的後續邏輯
for (i = 0; i if (!data[i]) continue; //無法處理undefined資料
total = data[i];
}
和break語句類似,有標籤的continue語句可以用在嵌套的迴圈中,用以跳出層次嵌套的迴圈體邏輯。同樣和break語句類似,在continue語句和labname之間不能有換行。
iiii.return
回想一下,函數呼叫的一種表達式,而且所有的表達式都有值。函數中的return語句即是指函數呼叫後的回傳值。這裡是return語句的語法:
return expression;
return語句只能在函數體內出現,如果不是的話會報到語法錯誤。執行到return語句的時候,函數終止執行,並傳回expression的值給呼叫程式。例如:
function square(x) {return x * x} //一個包含return的語句函數
square(4) //執行為16
如果沒有return語句,函數呼叫僅依序執行函數體內的每一語句直到函數結束,最後傳回呼叫程式。在這種情況下,呼叫表達式的結果是undefined。 return語句經常作為函數內最後的語句出現,但並不是說一定要放在函數的最後,即使在執行return語句的時候還有很多程式碼沒有執行到,這時候函數也還回傳呼叫程式。
return語句可以單獨使用而不必帶有expression,這樣的話函數也會想呼叫程式回傳undefined.例如:
//若參數是null或undefined立即回傳
if (!o) return;
//其它邏輯
由於javascript可以自動插入分號,因此,return關鍵字和它後面的表達式之間不能有換行。
iiiii.throw語句
所謂異常(excepion)是當發生了某種異常情況或錯誤時產生的一個訊號。拋出異常,就是用訊號通知發生了錯誤或異常狀況。捕獲異常是指處理這個訊號,拋出異常,就是用訊號通知發生了錯誤或異常狀況。捕獲異常是指處理這個訊號,即採取必要的手段從異常中匯豐。在javascript中,當產生運行時錯誤或程式使用throw語句時就會明確的拋出異常。使用try/catch/finally語句可以捕捉異常,下一節會對它作詳細介紹。
throw語句的語法如下:
throw expression
expression的值可以是任意型別的。可以拋出一個代表錯誤碼的數組,或是包含可錯誤訊息的字串。當javascript解釋器拋出異常的時候,通常會採用Eeeor類型或其子類型,當然也可以使用它們。一個error物件有一個那麼熟悉表示錯誤類型,一個message屬性用來傳遞建構函數的字串(參考第三部分的Error類別),在下面的例子中,當使用非法參數呼叫函數時就拋出一個Error對象:
function fa(x) {
 

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Dreamweaver CS6
視覺化網頁開發工具

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

SublimeText3漢化版
中文版,非常好用