Javascript核心讀書(shū)有感之語(yǔ)句
來(lái)源:易賢網(wǎng) 閱讀:994 次 日期:2015-02-13 11:02:41
溫馨提示:易賢網(wǎng)小編為您整理了“Javascript核心讀書(shū)有感之語(yǔ)句”,方便廣大網(wǎng)友查閱!

這篇文章主要介紹了Javascript核心讀書(shū)有感之語(yǔ)句,需要的朋友可以參考下

在javascript中,表達(dá)式是短語(yǔ),那么語(yǔ)句(statement)就是整句或命令。正如英文語(yǔ)句以句號(hào)結(jié)尾,javascript以分號(hào)結(jié)尾。

表達(dá)式計(jì)算出一個(gè)值,但語(yǔ)句使某件事發(fā)生。

“使某件事發(fā)生”的一個(gè)方法是計(jì)算帶有副作用的表達(dá)式。諸如賦值和函數(shù)調(diào)用這些有副作用的表達(dá)式,是可以作為單獨(dú)的語(yǔ)句的。這種把表達(dá)式當(dāng)做語(yǔ)句的用法也稱(chēng)做表達(dá)式語(yǔ)句(expression statement)。類(lèi)似的語(yǔ)句還有聲明語(yǔ)句(declaration statement),聲明語(yǔ)句用來(lái)聲明新變量或者定義新函數(shù)。

javascript程序就是一系列的可執(zhí)行語(yǔ)句的集合,默認(rèn)情況下,javascript解釋器依照編寫(xiě)順序依次執(zhí)行。另一種“使某件事情”發(fā)生的方法就是改變語(yǔ)句的默認(rèn)執(zhí)行順序:

1.條件語(yǔ)句(conditional)語(yǔ)句:javascript解釋器可以根據(jù)一個(gè)表達(dá)式的值來(lái)判斷;來(lái)執(zhí)行還是跳過(guò)這些語(yǔ)句,例如if和switch語(yǔ)句。

2.循環(huán)語(yǔ)句(loop)語(yǔ)句:可以重復(fù)執(zhí)行的語(yǔ)句,例如while和for語(yǔ)句

3.跳轉(zhuǎn)(jump)語(yǔ)句:可以讓解釋器跳轉(zhuǎn)至程序的其它部分繼續(xù)執(zhí)行、例如break、return和throw語(yǔ)句

接下來(lái)本文將介紹javascript中各式各樣的語(yǔ)句和其語(yǔ)法。本章最后對(duì)這些語(yǔ)句做了總結(jié)。一個(gè)javascript程序無(wú)非是以分隔分割的語(yǔ)句集合,所以一旦掌握了javascript語(yǔ)句,就可以編寫(xiě)javascript程序了。

1.表達(dá)式語(yǔ)句

賦值語(yǔ)句是一種比較重要的表達(dá)式語(yǔ)句,它的作用就是改變一個(gè)變量的值,就像執(zhí)行一條賦值語(yǔ)句一樣:例如

代碼如下:

greet = "hello" + name;

i *= 3;

遞增運(yùn)算符(++)和遞減運(yùn)算符(--)和賦值語(yǔ)句有關(guān)。它們的作用是改變一個(gè)變量的值,就像執(zhí)行一條賦值語(yǔ)句一樣。

代碼如下:

counter++;

delete運(yùn)算符的重要作用就是刪除一個(gè)對(duì)象的屬性(或數(shù)組的元素),所有它一般作為語(yǔ)句使用,而不是作為復(fù)雜表達(dá)式的一部分。

代碼如下:

delete o.x;

函數(shù)調(diào)用是表達(dá)式語(yǔ)句的另外一個(gè)大類(lèi),例如

代碼如下:

alert(greet);

window.close();

雖然這些客戶(hù)端函數(shù)都是表達(dá)式,但它們對(duì)web瀏覽器造成了一定的影響。所以我們認(rèn)為也是語(yǔ)句,調(diào)用一個(gè)沒(méi)有副作用的函數(shù)是沒(méi)有意義的,除非它是復(fù)雜的表達(dá)式或賦值語(yǔ)句的一部分,例如。不可能隨便把一個(gè)余弦值丟棄;

Math.cos(x);

相反,得出余弦值就得把它賦值給一個(gè)變量,以便將來(lái)使用這個(gè)值:

var cx = Math.cos(x);

再次提醒各位,每行代碼就是以分號(hào)結(jié)束的。

2.復(fù)合語(yǔ)句和空語(yǔ)句

可以用逗號(hào)運(yùn)算符將幾個(gè)表達(dá)式連接在一起,形成一個(gè)表達(dá)式。同樣,javascript還可以講多條語(yǔ)句聯(lián)合在一起,形成一個(gè)復(fù)合語(yǔ)句(compound statement)。只需花括號(hào)將多條語(yǔ)句括起來(lái)即可。因此,下面幾行代碼可以當(dāng)成一條單獨(dú)的語(yǔ)句,使用在javascript任何希望使用一條語(yǔ)句的地方。

代碼如下:

{

x = Math.PI;

cx = Math.cos(x);

console.log("cos(π)=" + cx);

}

關(guān)于語(yǔ)句塊有幾點(diǎn)需要注意:第一,語(yǔ)句塊不需要分號(hào)。塊中的元素語(yǔ)句必須以分號(hào)結(jié)尾,但語(yǔ)句塊不需要。

第二,語(yǔ)句塊中的行都有縮進(jìn),這不是必須的,但整齊的縮進(jìn)能使代碼可讀性更強(qiáng),更容易理解。

第三,javascript沒(méi)有塊級(jí)作用域,在語(yǔ)句塊中聲明的變量并不是語(yǔ)句塊所私有的。(參考3章10節(jié)第一小節(jié))

將很多條語(yǔ)句合并成一個(gè)大語(yǔ)句塊的做法在javascript編程中非常常見(jiàn)。類(lèi)似的表達(dá)式通常包含子表達(dá)式一樣,很多javascript包含其它子語(yǔ)句,從形式來(lái)講,javascript通常允許一個(gè)語(yǔ)句塊包含一條子語(yǔ)句。例如:while循環(huán)的循環(huán)體就可以只包含一條語(yǔ)句。使用語(yǔ)句塊,可以將任意數(shù)量的語(yǔ)句放到這個(gè)塊中,這個(gè)語(yǔ)句塊可以當(dāng)做一條語(yǔ)句來(lái)使用。

在javascript中,當(dāng)希望多條語(yǔ)句被當(dāng)做一條語(yǔ)句使用時(shí),使用符合語(yǔ)句來(lái)替代。空語(yǔ)句(empty statement)則恰好相反,它允許包含0條語(yǔ)句??照Z(yǔ)句如下所示:

;//分號(hào)

javascript解釋器在執(zhí)行空語(yǔ)句時(shí)顯然不執(zhí)行任何動(dòng)作,但實(shí)踐證明:當(dāng)創(chuàng)建一個(gè)具有空循環(huán)體的循環(huán)時(shí),空語(yǔ)句有時(shí)是很有用的,例如下面的for循環(huán)

代碼如下:

//初始化一個(gè)數(shù)組a

for (i = 0; i < a.length; a[i++] = 0);

在這個(gè)循環(huán)中,所有的操作都在表達(dá)式a[i++]=0中完成,這里并不需要任何循環(huán)體。然而javascript需要循環(huán)體中至少包含一條語(yǔ)句,因此這里只使用了一個(gè)單獨(dú)的分號(hào)來(lái)表示一條空語(yǔ)句。

注意,在for循環(huán)、while循環(huán)或if語(yǔ)句的右邊園括號(hào)的分號(hào)很不起眼,這很可能造成 一些致命的bug,而這些bug很難定位到。例如下面的代碼的執(zhí)行結(jié)果很可能就是作者不想要的效果:

代碼如下:

if((a==0)||(b==0)); //這一行代碼什么也沒(méi)做....

o = null; //這一行代碼總會(huì)執(zhí)行

如果有特殊目的使用空語(yǔ)句,最好在代碼中添加注釋?zhuān)@樣能更清楚的說(shuō)明這條空語(yǔ)句是有用的

代碼如下:

for (i = 0; i < a.length; a[i++] = 0) /*empty*/;

3.聲明語(yǔ)句

var和function都是聲明語(yǔ)句,它們聲明或定義變量或函數(shù)。這些語(yǔ)句定義標(biāo)識(shí)符(變量名和函數(shù)名)并給其賦值,這些標(biāo)識(shí)符可以在程序任意地方使用。聲明語(yǔ)句本身什么也不做,但它有一個(gè)重要意義:通過(guò)創(chuàng)建變量和函數(shù),可以更好的組織代碼的語(yǔ)義。

接下幾節(jié)將講述var語(yǔ)句和function語(yǔ)句,但并不包含變量和函數(shù)的全部?jī)?nèi)容。

i.var

var語(yǔ)句用來(lái)聲明一個(gè)或者多個(gè)變量,它的語(yǔ)法如下:

var name_1[ = value_1][, ..., name_n[ = value_n]]

關(guān)鍵字var之后跟隨的是要聲明的變量列表,列表中的每一個(gè)變量都可以帶有初始化表達(dá)式,可用于指定它的初始值。例如:

代碼如下:

var i; //一個(gè)簡(jiǎn)單的變量

var j = 0; //一個(gè)帶有初始值的變量

var p, q; //兩個(gè)變量

var greet = "hello" + name; //更復(fù)雜的初始化表達(dá)式

var x = 2.34,y = Math.cos(0.75),r, theta; //很多變量

var x = 2,y = x * x; //第二個(gè)變量使用了第一個(gè)變量

var x = 2,

f = function(x) {return x * x}, //每個(gè)變量都獨(dú)占一行

y = f(x)

如果var語(yǔ)句出現(xiàn)在函數(shù)體內(nèi),那么定義的是一個(gè)局部變量,其作用域就是這個(gè)函數(shù)。如果在頂層代碼中使用var語(yǔ)句,那么它聲明的是全局變量,在整個(gè)javascript中,都是可見(jiàn)的。在第三章10節(jié)提到:全局變量是全局對(duì)象的屬性,然后和其它全局對(duì)象屬性不同的是,var聲明的變量是無(wú)法通過(guò)delete刪除的。

如果var語(yǔ)句中的變量沒(méi)有指定初始化表達(dá)式,那么這個(gè)變量的值初始為undefined。所以,在聲明語(yǔ)句之前的變量值就是undefined。

需要注意的是,var語(yǔ)句同樣可以作為for循環(huán)或者for/in循環(huán)的組成部分。(在循環(huán)之前聲明的變量聲明一樣,這里聲明變量也會(huì)"提前"),例如:

代碼如下:

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

for (var i = 0, j = 10; i < 10; i++, j--) console.log(i * j);

for (var i in o)console.log(i);

注意,多次聲明同一變量是無(wú)所謂的。

ii.function

關(guān)鍵字function用來(lái)聲明函數(shù)的,我們已經(jīng)學(xué)過(guò)函數(shù)表達(dá)式(4.3).函數(shù)定義可以寫(xiě)成語(yǔ)句的形式。例如:下面示例代碼中的兩種定義寫(xiě)法:

代碼如下:

var f = function f(x) {return x + 1;} //將表達(dá)式賦值給一個(gè)變量

function f(x){return x + 1;} //含有變量名的語(yǔ)句

函數(shù)聲明的語(yǔ)法如下:

代碼如下:

function funcname([arg1[, arg2[..., argn]]]) {

statements

}

funcname是要聲明的函數(shù)的名稱(chēng)標(biāo)識(shí)符。函數(shù)名之后是參數(shù)列表,參數(shù)之間使用逗號(hào)隔開(kāi)。當(dāng)調(diào)用函數(shù)的時(shí)候,這些標(biāo)識(shí)符則指代傳入函數(shù)的實(shí)參。

函數(shù)體是由javascript語(yǔ)句組成的,語(yǔ)句數(shù)量不限,且用花括號(hào)括起來(lái)。在定義函數(shù)時(shí),并不執(zhí)行函數(shù)體內(nèi)的語(yǔ)句,它和調(diào)用函數(shù)時(shí)待執(zhí)行的新函數(shù)對(duì)象相關(guān)聯(lián)。注意,function函數(shù)語(yǔ)句里的花括號(hào)是必須的,這和while循環(huán)和其它一些語(yǔ)句鎖使用的語(yǔ)句塊是不同的,即使函數(shù)體只有一條語(yǔ)句,仍然需要花括號(hào)將其括起來(lái)。

代碼如下:

function hyteus(x, y) {

return Math.sqrt(x * x + y * y);

}

hyteus(1, 2) //=>2.23606797749979

function facial(n) { //一個(gè)遞歸函數(shù)

if (n <= 1) return 1;

return n * facial(n - 1);

}

facial(11) //=>39916800

函數(shù)的聲明通常出現(xiàn)在javascript代碼的最頂部,也可以嵌套在其他函數(shù)體內(nèi)。但在嵌套時(shí),函數(shù)聲明只能出現(xiàn)在所嵌套的函數(shù)頂部。也就是說(shuō):函數(shù)定義不能出現(xiàn)在if、while、或其他語(yǔ)句中。

和var語(yǔ)句一樣,函數(shù)聲明語(yǔ)句創(chuàng)建的變量也是不可刪除的。但是這些變量不是只讀的,變量值可以重寫(xiě)。

4.條件語(yǔ)句

條件語(yǔ)句是通過(guò)判斷指定的表達(dá)式的值是否來(lái)執(zhí)行或跳過(guò)某些語(yǔ)句。這些語(yǔ)句是代碼的”決策點(diǎn)“,有時(shí)稱(chēng)為”分支“。如果javascript解釋器是按照代碼的”路徑“執(zhí)行的。條件語(yǔ)句就是這條路上的分叉點(diǎn)。程序到達(dá)這里必須選擇一條路徑來(lái)繼續(xù)執(zhí)行。

i.if語(yǔ)句

if語(yǔ)句是基本的控制語(yǔ)句,準(zhǔn)確的說(shuō),它讓程序有條件的執(zhí)行,這種語(yǔ)句有兩種形式:第一種是

代碼如下:

if (expression)

statement

這種形式中,判斷expression 的值,如果是真,執(zhí)行statement語(yǔ)句,如果是假值,就不執(zhí)行statement.例如

代碼如下:

if (username == null) //如果username是null或undefined

username = "jack wong"; //對(duì)其進(jìn)行定義

需要注意的是,if語(yǔ)句括住expression的園括號(hào)是必須的。

javascript語(yǔ)法規(guī)定,if關(guān)鍵字和帶園括號(hào)的表達(dá)式之后必須跟隨一條語(yǔ)句。但可以使用語(yǔ)句塊將多條語(yǔ)句合成一條。因此,if語(yǔ)句的形式如下所示:

代碼如下:

if (!address) {

address = "";

message = "please mailing address"

}

if語(yǔ)句的第二種形式引入了else從句,當(dāng)expression的值是false值時(shí)執(zhí)行else 邏輯

代碼如下:

if (expression)

statement1

else

statement2

例如以下代碼

代碼如下:

if (n == 1)

console.log("1 new message");

else

console.log("you have" + n + "new message");

當(dāng)if/else語(yǔ)句中,嵌套使用if語(yǔ)句時(shí),必須注意確保else語(yǔ)句匹配正確的if語(yǔ)句??紤]如下代碼:

代碼如下:

i = j = 1;

k = 2;

if (i == j)

if (j == k)

console.log("i equs k");

else

console.log("i dosent equal j"); //錯(cuò)誤??!

這個(gè)實(shí)例中,內(nèi)層的if語(yǔ)句構(gòu)成了外層if語(yǔ)句所需要的子句。但是,if和else的匹配關(guān)系不清晰(只有縮進(jìn)給了一點(diǎn)暗示)而且在這個(gè)例子里,縮進(jìn)給出的暗示是錯(cuò)誤的,因?yàn)閖avascript解釋器是這么理解的。

代碼如下:

if (i == j) {

if (j == k)

console.log("i equs k");

else

console.log("i dosent equal j");

}

和大多編程語(yǔ)言一樣,javascript中的if、else匹配規(guī)則是,else總是和就近的if語(yǔ)句匹配,為了讓個(gè)例子的可讀性更強(qiáng),更容易理解,更方便維護(hù)和調(diào)試,應(yīng)當(dāng)使用花括號(hào)

代碼如下:

if (i == j) {

if (j == k) {

console.log("i equs k");

} else { //花括號(hào)使代碼的結(jié)果更清晰

console.log("i dosent equal j");

}

}

許多程序員都將有if和else語(yǔ)句主體用花括號(hào)括起來(lái)的習(xí)慣(就像類(lèi)似while循環(huán)這樣的符合語(yǔ)句中一樣),即使每條分支只有一條語(yǔ)句,但這樣做能避免剛才的程序歧義問(wèn)題。

ii.else if

if/else語(yǔ)句通過(guò)判斷一個(gè)表達(dá)式的計(jì)算結(jié)果來(lái)選擇兩條分支中的一條。當(dāng)代碼中有許多條分支的時(shí)候應(yīng)該怎么辦呢?一種解決的辦法是使用else if語(yǔ)句。else if并不是真正的javascript語(yǔ)句,它只不過(guò)是多條if / else語(yǔ)句連接在一起的寫(xiě)法。

代碼如下:

if (n == 1) {

//執(zhí)行代碼塊 1

} else if (n == 2) {

//執(zhí)行代碼塊2

} else if (n == 3) {

//執(zhí)行代碼塊3

} else {

//之前的條件都為false,則執(zhí)行代碼塊4

}

這種代碼沒(méi)有什么特別之處,它由多條if語(yǔ)句組成,每條if語(yǔ)句的else的從句又包含另外一條if語(yǔ)句。可以用if語(yǔ)句的嵌套形式來(lái)完成語(yǔ)法上的等價(jià)代碼,但與此相比,顯然else if的寫(xiě)法更加清晰也更可取。

iii.switch

if語(yǔ)句在程序執(zhí)行的過(guò)程中,創(chuàng)建一支分支,并且可以使用else if來(lái)處理多條分支。然后,當(dāng)所有的分支都依賴(lài)同一個(gè)表達(dá)式的值時(shí),else if并不是最佳的解決方案。在這種情況下,重復(fù)計(jì)算多條if語(yǔ)句中的表達(dá)式是非常浪費(fèi)的做法。

switch語(yǔ)句適合處理這種情況。關(guān)鍵字switch之后緊跟著園括號(hào)括起來(lái)的一個(gè)表達(dá)式。隨后是花括號(hào)括起來(lái)的代碼塊。

代碼如下:

switch (expression) {

statements

}

然而switch語(yǔ)句完整的語(yǔ)法要比這更復(fù)雜一些。case之后是一個(gè)表達(dá)式和冒號(hào),case和標(biāo)記語(yǔ)很類(lèi)似,只是這個(gè)標(biāo)記語(yǔ)并沒(méi)有名字。

它只和他后面的表達(dá)式關(guān)聯(lián)在一起。當(dāng)執(zhí)行執(zhí)行這條switch語(yǔ)句時(shí),它首先計(jì)算expression的值,然后查找case子句的表達(dá)式是否和expression的值相同。(這里的相同是按照“===”運(yùn)算符進(jìn)行比較的),如果匹配case,它將會(huì)執(zhí)行對(duì)應(yīng)的代碼。如果找不到匹配的case,它將會(huì)執(zhí)行"default:"標(biāo)簽中的代碼塊。如果沒(méi)有“default:”標(biāo)簽,switch將跳過(guò)所有的代碼塊。

switch語(yǔ)句是非常容易混淆的,用例子介紹會(huì)比較清晰一點(diǎn),下面的switch語(yǔ)句和方才的if/else語(yǔ)句是等價(jià)的

代碼如下:

switch (n) {

case 1: //如果n ===1從這里開(kāi)始

//執(zhí)行代碼塊1

break;

case 2:

//執(zhí)行代碼塊2

break;

case 3:

//執(zhí)行代碼塊3

break;

default:

//執(zhí)行代碼塊4

break;

}

需要注意的是,每個(gè)case語(yǔ)句的結(jié)尾處都使用了關(guān)鍵字break。我們將后面介紹break語(yǔ)句,break語(yǔ)句可以使解釋器跳出switch語(yǔ)句或循環(huán)語(yǔ)句。在switch中,case只是指明了要執(zhí)行的代碼起點(diǎn),但沒(méi)有指明終點(diǎn)。如果沒(méi)有break語(yǔ)句,那么switch語(yǔ)句就從expression的值的匹配的case標(biāo)簽處代碼開(kāi)始執(zhí)行,依次執(zhí)行后續(xù)的語(yǔ)句,一直到整個(gè)switch代碼塊結(jié)束。當(dāng)然,如果在函數(shù)中使用switch語(yǔ)句,可以使用return來(lái)替換break,return和break都用于終止switch語(yǔ)句,也會(huì)防止一個(gè)case語(yǔ)句執(zhí)行完繼續(xù)執(zhí)行下一個(gè)case語(yǔ)句塊。

下面的語(yǔ)句貼近實(shí)戰(zhàn),它根據(jù)值的類(lèi)型將該值轉(zhuǎn)換為字符串。

代碼如下:

function convert(x) {

switch (typeof x) {

case 'number': //將數(shù)字轉(zhuǎn)換為16進(jìn)制

return x.toString(16);

case 'string':

return '"' + x + '"'; //返回兩段帶雙引號(hào)的字符串。

default: //使用普通方法轉(zhuǎn)換其它類(lèi)型

return String(x);

}

}

console.log(convert(100255114)) //=>5f9c58a

注意,在上面的兩個(gè)例子中,case關(guān)鍵字后跟隨的是數(shù)字和字符串直接量,在實(shí)際中這是switch最常見(jiàn)的用法,但是ECMAScript標(biāo)準(zhǔn)允許每個(gè)關(guān)鍵字跟隨任意的表達(dá)式。

switch語(yǔ)句首先計(jì)算switch 關(guān)鍵字后的表達(dá)式,然后按照從上到下的順序計(jì)算每個(gè)case后的表達(dá)式,知道執(zhí)行到case的表達(dá)式的值和switch的表達(dá)式的值相等時(shí)為止。由于對(duì)每個(gè)case的匹配操作實(shí)際上是“===”恒等運(yùn)算符比較,而不是“==”,因此表達(dá)式和case的匹配并不會(huì)做任何類(lèi)型轉(zhuǎn)換。

每次執(zhí)行switch語(yǔ)句的時(shí)候,并不是所有的case表達(dá)式都能執(zhí)行到,因此,應(yīng)當(dāng)避免帶有副作用的case表達(dá)式,比如函數(shù)調(diào)用的表達(dá)式和賦值表達(dá)式。最安全的做法就是在case表達(dá)式中使用常量表達(dá)式。

前面提到過(guò),switch表達(dá)式與所有的case表達(dá)式都不匹配,則執(zhí)行標(biāo)記為“default:”的語(yǔ)句塊,如果沒(méi)有"default:"標(biāo)簽,則switch整個(gè)語(yǔ)句都跳過(guò)。在之前的例子中,“default:”標(biāo)簽都出現(xiàn)在switch末尾,位于所有case標(biāo)簽之后,當(dāng)然這是最合理也是最常用的寫(xiě)法。實(shí)際上,“default:”標(biāo)簽可以放在switch語(yǔ)句內(nèi)任何地方。

5.循環(huán)。

為了理解條件語(yǔ)句,可以將javascript中的代碼想成一條條分支路徑。循環(huán)語(yǔ)句(looping statement)就是程序路徑的一個(gè)回路,可以讓一部分代碼重復(fù)執(zhí)行。javascript中有四種循環(huán)語(yǔ)句:while、do/while、for、for/in下面幾節(jié)會(huì)一次講解他們。其中最常用的循環(huán)就是數(shù)組元素的遍歷,(7.6會(huì)詳細(xì)討論這種循環(huán)和使用數(shù)組類(lèi)定義的特殊循環(huán)方法。)

i.while

if語(yǔ)句是一種基本的控制語(yǔ)句,用來(lái)選擇執(zhí)行程序的分支語(yǔ)句。和if一樣,while語(yǔ)句也是一個(gè)基本的循環(huán)語(yǔ)句,它的語(yǔ)法如下:

代碼如下:

while (expression)

statement

在執(zhí)行while語(yǔ)句之前,javascript解釋器首先計(jì)算expression的值,如果它的值是假值,那么程序?qū)⑻^(guò)循環(huán)體中的邏輯statement轉(zhuǎn)而執(zhí)行程序中的下一條語(yǔ)句。如果它的值是真值,則執(zhí)行循環(huán)體statement內(nèi)的邏輯,然后再計(jì)算表達(dá)式expression的值,種循環(huán)會(huì)一直持續(xù)下去,知道expression的值為假值為止。換一種說(shuō)法 就是表達(dá)式為expression是真值的時(shí)候則循環(huán)執(zhí)行statement,注意,使用while(true)則會(huì)創(chuàng)建一個(gè)死循環(huán)。

通常來(lái)說(shuō),我們不想讓javascript反復(fù)執(zhí)行同一操作。在幾乎每一次循環(huán)中,都會(huì)有一個(gè)或多個(gè)變量隨著循環(huán)而迭代改變。正是由于改變了變量這些變量,因此每次循環(huán)執(zhí)行的statement的操作也不盡相同,而且,如果改變變量在expression中用到,那么每次循環(huán)表達(dá)式的值也不同。這一點(diǎn)非常重要,負(fù)責(zé)初始值為真值的表達(dá)式永遠(yuǎn)是真值,循環(huán)也不會(huì)結(jié)束,下面的這個(gè)示例所示while循環(huán)輸出0-9值。

代碼如下:

var count = 0;

while (count < 10) {

console.log(count);

count++;

}

可以發(fā)現(xiàn),在這個(gè)例子中,變量count的初始值為0,在循環(huán)的過(guò)程中,它的值每次都遞增1,當(dāng)循環(huán)執(zhí)行了十次。表達(dá)式的值就編程了false,這時(shí)while就會(huì)結(jié)束,javascript解釋器將執(zhí)行程序下一條語(yǔ)句。大多循環(huán)都有一個(gè)像count這樣的計(jì)數(shù)器變量。盡管計(jì)數(shù)器常用i j k這樣的變量名,但如果想讓代碼的可讀性更強(qiáng),就應(yīng)當(dāng)使用更具體的語(yǔ)法名。

ii.do/while

do/while循環(huán)和while循環(huán)非常相似,只不過(guò)它是在循環(huán)的尾部而不是頂部檢測(cè)循環(huán)表達(dá)式,這就意味這循環(huán)體至少執(zhí)行一次。do/while循環(huán)的語(yǔ)法如下:

代碼如下:

do

statement

while(expression);

do/while循環(huán)并不像while循環(huán)那么常用。這是因?yàn)樵趯?shí)踐中想要循環(huán)至少執(zhí)行一次的情況并不常見(jiàn)。下面是一個(gè)do/while循環(huán)的例子

代碼如下:

function printArray(a) {

var len = a.length,

i = 0;

if (len == 0)

console.log("空數(shù)組");

else

do {

console.log(a[i]);

} while (++i < len);

}

printArray([1,5,2,6])

在do/while循環(huán)和普通while循環(huán)之間有兩點(diǎn)語(yǔ)法方面的不同之處。首先,do循環(huán)要求必須使用關(guān)鍵字do來(lái)標(biāo)識(shí)循環(huán)的開(kāi)始,用while變標(biāo)識(shí)循環(huán)的結(jié)尾并進(jìn)入循環(huán)條件判斷;其次,和while循環(huán)不同,do循環(huán)使用分號(hào)結(jié)尾的。如果while的循環(huán)體使用花括號(hào)括起來(lái),則while循環(huán)也不使用分號(hào)結(jié)尾。

iii.for

for語(yǔ)句提供了一種比while更方便的循環(huán)語(yǔ)句控制結(jié)構(gòu)。for語(yǔ)句對(duì)常用的循環(huán)模式做了一些簡(jiǎn)化。大部分的循環(huán)都具有特定的計(jì)數(shù)器變量。在循環(huán)開(kāi)始之前要初始化這個(gè)變量,然后在每次循環(huán)之前檢查下它的值。最后,計(jì)數(shù)器變量做自增操作,否則就在循環(huán)結(jié)束后、下一次判斷前做修改。在這類(lèi)循環(huán)中,計(jì)數(shù)器的三個(gè)關(guān)鍵操作是初始化、檢測(cè)和更新。for語(yǔ)句就將這三部操作明確聲明為循環(huán)語(yǔ)法的一部分,各自使用一個(gè)表達(dá)式來(lái)表示。for語(yǔ)句的語(yǔ)法如下:

代碼如下:

for (initialize; test; increment)

statement

intialize、test、increment三個(gè)表達(dá)式之間使用分號(hào)分隔,他們負(fù)責(zé)初始化操作、循環(huán)條件判斷和計(jì)數(shù)器變量的更新。將它們放在循環(huán)的第一行會(huì)更容易理解for循環(huán)正在做什么,而且也可防止忘記初始化或者遞增計(jì)數(shù)器變量。

要解釋for循環(huán)是怎么樣工作的,最簡(jiǎn)單方法就是列出一個(gè)與之等價(jià)的while循環(huán)

代碼如下:

initialize

while (test) {

statement

increment;

}

換句話(huà)說(shuō),initialize表達(dá)式只在循環(huán) 開(kāi)始之前執(zhí)行一次。初始化表達(dá)式應(yīng)當(dāng)具有副作用(通常是一條賦值語(yǔ)句)。javascript同樣允許初始化表達(dá)式中帶有var變量聲明語(yǔ)句,這樣的話(huà)就可以聲明并初始化一個(gè)變量。每次循環(huán)之前會(huì)執(zhí)行test表達(dá)式,并判斷表達(dá)式的結(jié)果來(lái)決定是否執(zhí)行循環(huán)體。每次循環(huán)之前會(huì)執(zhí)行test表達(dá)式,并判斷其結(jié)果是否來(lái)執(zhí)行循環(huán)體,如果test結(jié)果為真值,則執(zhí)行循環(huán)體中的statement。最后,執(zhí)行increment表達(dá)式。同樣為了有用起見(jiàn),這里的increment表達(dá)式也必須有副作用。通常來(lái)講,它不是一個(gè)賦值表達(dá)式就是一個(gè)由“++”、“--”運(yùn)算符構(gòu)成的表達(dá)式。

上文的while循環(huán)可以使用for循環(huán)來(lái)從寫(xiě)

代碼如下:

for (var count = 0; count < 10; count++)

console.log(count)

當(dāng)然,有些循環(huán)更加復(fù)雜,而且循環(huán)中一次迭代多個(gè)變量。在javascript,這種情況必須用到逗號(hào)運(yùn)算符,它將初始化表達(dá)式和自增表達(dá)式合并入一個(gè)表達(dá)式中以用于for循環(huán)。

代碼如下:

var i, j;

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

console.log(i * j);

到目前為止,在示例代碼中的循環(huán)變量都是數(shù)字。當(dāng)然是數(shù)字是最常用的,但不是必須的。下面這段代碼就使用for循環(huán)來(lái)遍歷表數(shù)據(jù)結(jié)果,并返回鏈表中最后一個(gè)對(duì)象(也就是第一個(gè)不包含next屬性的對(duì)象)

代碼如下:

function tail(o) { //返回鏈表的最后一個(gè)節(jié)點(diǎn)對(duì)象

for (; o.next; o = o.next) /*empty*/ //根據(jù)判斷o.next是不是真值來(lái)執(zhí)行遍歷

return o;

}

需要注意的是,這段代碼不包含initialize表達(dá)式,for循環(huán)中的那三個(gè)表達(dá)式中的人和一個(gè)都可以忽略,但兩個(gè)分號(hào)必不可少。如果省略test表達(dá)式,那么將是一個(gè)死循環(huán)。同樣和while(ture)類(lèi)型,死循環(huán)的令一種寫(xiě)法是for(;;)。

iiii.for/in

for/in語(yǔ)句使用for關(guān)鍵字,但它和常規(guī)的for循環(huán)是不同的一類(lèi)循環(huán)。for/in循環(huán)的語(yǔ)法如下

代碼如下:

for (variable in object)

statement

variable通常是一個(gè)變量名,也可以是一個(gè)可以產(chǎn)生左值的表達(dá)式或者一個(gè)通過(guò)var語(yǔ)句聲明的變量??傊且粋€(gè)適用于賦值表達(dá)式左側(cè)的值。object是一個(gè)表達(dá)式,這個(gè)表達(dá)式的計(jì)算結(jié)果是一個(gè)對(duì)象。同樣,statement是一個(gè)語(yǔ)句或語(yǔ)句塊,它構(gòu)成了循環(huán)的主體。

使用for循環(huán)來(lái)遍歷數(shù)組元素是非常簡(jiǎn)單的

代碼如下:

var a = [1, 3, 5, "44"];

for (var i = 0; i < a.length; i++) //i代表了數(shù)組元素的索引

console.log(a[i]) //輸出每個(gè)數(shù)組的元素

而for/in循環(huán)則是用來(lái)方便的遍歷對(duì)象成員屬性

代碼如下:

for (var p in o) //將屬性的名字賦值給變量p

console.log(o[p]); //輸出每一個(gè)屬性的值

在執(zhí)行 for/in語(yǔ)句的過(guò)程中,javascript解釋器首先計(jì)算object表達(dá)式。如果表達(dá)式為null或undefined,javascript解釋器將跳過(guò)循環(huán)并執(zhí)行后續(xù)的代碼。如果表達(dá)式等于一個(gè)原始值,這個(gè)原始值將會(huì)轉(zhuǎn)換為與之對(duì)于的包裝對(duì)象(wapper object)(3.6節(jié))。否則,expression本身已經(jīng)是對(duì)象了。javascript會(huì)依次枚舉對(duì)象的屬性來(lái)執(zhí)行循環(huán)。然而在每次循環(huán)之前,javascript都會(huì)計(jì)算variable表達(dá)式的值,并將屬性名(一個(gè)字符串)賦值給它。

需要注意的是,只要for/in循環(huán)中,varibale的值可以當(dāng)做賦值表達(dá)式的左值,它可以是任意表達(dá)式。每次循環(huán)都會(huì)計(jì)算這個(gè)表達(dá)式,也就是說(shuō)每次循環(huán)它計(jì)算的值可能不同。例如,可以使用下面的這段代碼將所有對(duì)象屬性復(fù)制到一個(gè)數(shù)組中:

代碼如下:

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數(shù)組只不過(guò)是一種特殊的對(duì)象,因此,for/in循環(huán)可以像枚舉對(duì)象屬性一樣枚舉數(shù)據(jù)索引。例如在上面的代碼之后添加這段代碼,就可以枚舉數(shù)據(jù)索引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將對(duì)象屬性復(fù)制到一個(gè)數(shù)組中

for(i in a)

document.write(i) //=>枚舉數(shù)據(jù)索引 0 1 2

其實(shí),for/in循環(huán)并不會(huì)遍歷對(duì)象的所有屬性,只有“可枚舉”(enumerable)的屬性才會(huì)遍歷到(參照6.7)。由于javascript語(yǔ)言核心所定義的內(nèi)置方法就不是“可枚舉的”。比如,所有的對(duì)象都有toString(),但for/in循環(huán)并不枚舉toString()這個(gè)屬性。除了內(nèi)置的方法之外,還有很多內(nèi)置對(duì)象的屬性是不可枚舉的(nonenumberable)。而代碼中定義的所有屬性和方法都是可枚舉的(6.7節(jié)會(huì)講到,但ECMAScript5中有特殊手段可以使屬性變?yōu)椴豢擅杜e)。

對(duì)象可以繼承其它對(duì)象的屬性,那行繼承自定義屬性(6.2.ii)也可以使用for/in枚舉出來(lái)。

如果for/in的循環(huán)體刪除了還未枚舉的屬性,那么這個(gè)屬性將不會(huì)再枚舉。如果循環(huán)體定義了對(duì)象的 新屬性,這些屬性通常也不會(huì)枚舉到(不過(guò)。javascript有些實(shí)現(xiàn)可以枚舉那么些在循環(huán)體中增加的屬性)。

屬性枚舉的順序

ECMAScript規(guī)范并沒(méi)有指定for/in循環(huán)按照何種順序來(lái)枚舉對(duì)象的屬性。但實(shí)際上,主流的瀏覽器廠(chǎng)商javascript實(shí)現(xiàn)是按照屬性定義的先后順序來(lái)枚舉簡(jiǎn)單對(duì)象的屬性,先定義的屬性先枚舉。如果使用對(duì)象直接量的形式創(chuàng)建對(duì)象,則將按照直接量中屬性的出現(xiàn)順序枚舉。(有一些網(wǎng)和javascript庫(kù)是依賴(lài)這種枚舉順序的,而瀏覽器廠(chǎng)商大多不修改這個(gè)順序),在下面的情況下,枚舉順序取決于具體的實(shí)現(xiàn)(并非交互)

1.對(duì)象繼承了可枚舉屬性

2.對(duì)象具有整數(shù)數(shù)組索引的屬性

3.使用delete刪除了對(duì)象已有的屬性

4.使用Object.defineProperty()或者類(lèi)似的方法改變了對(duì)象屬性

6.跳轉(zhuǎn)

javascript中令一類(lèi)語(yǔ)句是跳轉(zhuǎn)語(yǔ)句(jump statement)。從語(yǔ)句理解,它可以使javascript執(zhí)行從一個(gè)位置跳轉(zhuǎn)到令一個(gè)位置。

break語(yǔ)句是跳轉(zhuǎn)到循環(huán)或其他的語(yǔ)句結(jié)束。continue語(yǔ)句是終止本次循環(huán)的執(zhí)行并開(kāi)始下一次循環(huán)的執(zhí)行。javascript中的語(yǔ)句可以命名或帶有標(biāo)簽,break和continue可以標(biāo)識(shí)目標(biāo)循環(huán)或者其它語(yǔ)句標(biāo)簽。

return語(yǔ)句可以讓解釋器跳出函數(shù)體的執(zhí)行。并提供本次調(diào)用的返回值。throw語(yǔ)句觸發(fā)或者拋出一個(gè)異常,它是與try/catch/finally語(yǔ)句一同使用的,這些語(yǔ)句指定了處理異常代碼邏輯。這是一種復(fù)雜的跳轉(zhuǎn)語(yǔ)句,當(dāng)拋出一個(gè)異常的時(shí)候,程序?qū)⑻磷罱拈]合異常辰星,這個(gè)異常程序可以是在同一個(gè)函數(shù)中或者更高層的調(diào)用棧中。

接下來(lái),描述每一種跳轉(zhuǎn)語(yǔ)句

i.標(biāo)簽語(yǔ)句

語(yǔ)句是可以添加標(biāo)簽的,標(biāo)簽是由語(yǔ)句前的標(biāo)識(shí)符和冒號(hào)組成:

identifier:statement

通過(guò)給語(yǔ)句定義標(biāo)簽,就可以在程序中任何地方通過(guò)標(biāo)簽名來(lái)引用這條語(yǔ)句??梢詫?duì)多條語(yǔ)句定義標(biāo)簽,盡管只有給語(yǔ)句塊定義標(biāo)簽時(shí)它才有更有用,比如循環(huán)語(yǔ)句或條件判斷語(yǔ)句。通過(guò)給循環(huán)定義一個(gè)標(biāo)簽名,可以在循環(huán)體內(nèi)部使用break和continue來(lái)退出循環(huán)或者直接挑戰(zhàn)到下一個(gè)循環(huán)開(kāi)始。break和continue是javascript中唯一可使用語(yǔ)句標(biāo)簽的語(yǔ)句(本章接下來(lái)會(huì)講述)。下面的例子,其中while循環(huán)定義了一個(gè)標(biāo)簽,continue語(yǔ)句使用了這個(gè)標(biāo)簽:

代碼如下:

mainloop: while (token != null) {

//忽略這里代碼...

continue mainloop; //跳轉(zhuǎn)到下一次循環(huán)

//忽略這里的代碼...

}

這里做標(biāo)簽的indentifier必須是一個(gè)合法的javascript標(biāo)識(shí)符,而不能是一個(gè)保留字。標(biāo)簽的命名空間和變量或函數(shù)的命名空間是不同的,因此可以使用同一個(gè)標(biāo)識(shí)符作為語(yǔ)句標(biāo)簽和作為變量名或函數(shù)名。語(yǔ)句標(biāo)簽只在它所起作用的語(yǔ)句(當(dāng)然可以在它的子句)內(nèi)是有定義的。一個(gè)語(yǔ)句標(biāo)簽不能和它內(nèi)部的語(yǔ)句標(biāo)簽重名,但在兩個(gè)代碼不相互嵌套的情況下是可以出現(xiàn)同名語(yǔ)句標(biāo)簽的。帶有標(biāo)簽的語(yǔ)句還可以帶有標(biāo)簽,也就是說(shuō),任何語(yǔ)句可以有很多個(gè)標(biāo)簽。

ii.break

單獨(dú)使用break語(yǔ)句的作用是立即退出最內(nèi)存的循環(huán)或switch語(yǔ)句。它的語(yǔ)法如下:

break;

由于它能夠使循環(huán)和switch語(yǔ)句退出,因此這種形式的break只能出現(xiàn)在這類(lèi)語(yǔ)句中才是合法的。

我們?cè)趕witch語(yǔ)句的例子中已經(jīng)見(jiàn)到果break語(yǔ)句。在循環(huán)中,無(wú)論出于什么原因,只要不想繼續(xù)執(zhí)行整個(gè)循環(huán),就可以用break提前退出。當(dāng)循環(huán)終止條件非常復(fù)雜時(shí),要函數(shù)體內(nèi)使用break語(yǔ)句實(shí)現(xiàn)這樣些條件判斷的做法要比直接在循環(huán)表達(dá)式中寫(xiě)出這個(gè)復(fù)雜的終止條件做法簡(jiǎn)單的多。

下面的例子中循環(huán)遍歷整個(gè)數(shù)組元素來(lái)查找某個(gè)特定的值,當(dāng)整個(gè)數(shù)組遍歷完成后正常退出循環(huán),如果找到 了需要查找的數(shù)組元素,則使用break語(yǔ)句退出循環(huán):

代碼如下:

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

if (a[i] == target) break;

}

javascript中同樣允許break關(guān)鍵字后跟隨一個(gè)語(yǔ)句標(biāo)簽,(只有標(biāo)識(shí)符,沒(méi)有冒號(hào))

break labelname;

當(dāng)break和標(biāo)簽一塊使用時(shí),程序?qū)⑻D(zhuǎn)到這個(gè)標(biāo)簽所識(shí)別的語(yǔ)句塊的結(jié)束,或者直接終止這個(gè)閉合語(yǔ)句塊的執(zhí)行。當(dāng)沒(méi)有任何閉合語(yǔ)句塊指定break所用的標(biāo)簽,這時(shí)會(huì)產(chǎn)生一個(gè)語(yǔ)法錯(cuò)誤。當(dāng)使用這種形式的break語(yǔ)句時(shí),帶標(biāo)簽的語(yǔ)句不應(yīng)該是循環(huán)或者switch語(yǔ)句,因?yàn)閎reak語(yǔ)句可以“跳出”任何閉合的語(yǔ)句塊。這里的語(yǔ)句可以是由花括號(hào)組起來(lái)的一組語(yǔ)句,使用同一個(gè)標(biāo)簽來(lái)識(shí)別一組語(yǔ)句。

break關(guān)鍵字和labelname之間不能換行。因?yàn)閖avascript可以給語(yǔ)句自動(dòng)補(bǔ)全省略掉的分號(hào),如果break關(guān)鍵字和標(biāo)簽之間有換行,javascript解釋器會(huì)認(rèn)為你在使用break不帶標(biāo)簽的最簡(jiǎn)形式,因此會(huì)在break后補(bǔ)充分號(hào).

當(dāng)你希望通過(guò)break來(lái)跳出非就近的循環(huán)體或者switch語(yǔ)句時(shí),就會(huì)用到帶標(biāo)簽的break語(yǔ)句。下面是示例代碼:

代碼如下:

var matrix = getData(); //從某處獲得一個(gè)二維數(shù)組

//將矩陣中所有元素進(jìn)行求和

var sum = 0,

success = false;

//從簽名處開(kāi)始,以便在報(bào)錯(cuò)時(shí)推出程序。

compure_sum: if (matrix) {

for (var x = 0; x < matrix.length; x++) {

var row = matrix[x];

if (!row) break compure_sum;

for (var y = 0; y < row.length; y++) {

var cell = row[y];

if (isNaN(cell)) break compure_sum;

sum += cell;

}

}

success = true;

}

//break語(yǔ)句跳轉(zhuǎn)至此

//如果success =false條件到達(dá)這里,說(shuō)明我們給出的矩陣中有錯(cuò)誤

//否則對(duì)矩陣中所有的元素進(jìn)行求和

最后,需要注意的是,不管break語(yǔ)句帶不帶標(biāo)簽,它的控制權(quán)都無(wú)法越過(guò)函數(shù)的邊界。比如:對(duì)于一條帶標(biāo)簽的函數(shù)定義語(yǔ)句來(lái)說(shuō),不能通過(guò)函數(shù)內(nèi)部通過(guò)這個(gè)標(biāo)簽來(lái)跳轉(zhuǎn)到函數(shù)外部.

iii.continue語(yǔ)句

continue語(yǔ)句和break語(yǔ)句非常類(lèi)似,但它不退出循環(huán),而是轉(zhuǎn)而執(zhí)行下一次循環(huán)。continue語(yǔ)句的語(yǔ)法和break的語(yǔ)句語(yǔ)法一樣簡(jiǎn)單

continue;

continue語(yǔ)句會(huì)也會(huì)帶有標(biāo)簽

continue lebname;

不管continue語(yǔ)句帶不帶標(biāo)簽,它只能在循環(huán)體使用,在其它地方使用將會(huì) 報(bào)語(yǔ)法錯(cuò)誤。

當(dāng)執(zhí)行到continue語(yǔ)句的時(shí)候,當(dāng)前的循環(huán)邏輯就終止了,隨即執(zhí)行下一次循環(huán),在不同類(lèi)型的循環(huán)中,continue的行為也有區(qū)別

1. 在while循環(huán)中,在循環(huán)開(kāi)始處指定expression會(huì)重復(fù)檢測(cè),如果檢測(cè)結(jié)果為true,循環(huán)體會(huì)從頭執(zhí)行。

2. 在do/while循環(huán)中,程序的執(zhí)行至今跳轉(zhuǎn)到循環(huán)的結(jié)尾處,這時(shí)會(huì)重新判斷循環(huán)條件,之后才會(huì)繼續(xù)下一次循環(huán)。

3. 在for循環(huán)中,首先會(huì)計(jì)算自增表達(dá)式,然后再檢測(cè)test表達(dá)式,用以判斷是否執(zhí)行循環(huán)體。

4. 在for/in循環(huán)中,循環(huán)開(kāi)始遍歷下一個(gè)屬性名,這個(gè)屬性名賦給了指定的變量。

需要注意continue語(yǔ)句在while和for循環(huán)中的區(qū)別,while循環(huán)直接進(jìn)入下一輪的循環(huán)條件判斷,但for循環(huán)首先計(jì)算器increment表達(dá)式,然后判斷循環(huán)條件。之前的章節(jié)討論了和while循環(huán)“等價(jià)”的for循環(huán)行為。但由于continue在這兩種循環(huán)中行為表現(xiàn)不同,因此使用while循環(huán)不可能完美的模擬等價(jià)的for循環(huán)。

下面這段代碼展示了不帶標(biāo)簽的continue語(yǔ)句,產(chǎn)生一個(gè)錯(cuò)誤的時(shí)候跳過(guò)當(dāng)前循環(huán)的后續(xù)邏輯

代碼如下:

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

if (!data[i]) continue; //不能處理undefined數(shù)據(jù)

total += data[i];

}

和break語(yǔ)句類(lèi)似,帶標(biāo)簽的continue語(yǔ)句可以用在嵌套的循環(huán)中,用以跳出層次嵌套的循環(huán)體邏輯。同樣和break語(yǔ)句類(lèi)似,在continue語(yǔ)句和labname之間不能有換行。

iiii.return

回想一下,函數(shù)調(diào)用的一種表達(dá)式,而且所有的表達(dá)式都有值。函數(shù)中的return語(yǔ)句即是指函數(shù)調(diào)用后的返回值。這里是return語(yǔ)句的語(yǔ)法:

return expression;

return語(yǔ)句只能在函數(shù)體內(nèi)出現(xiàn),如果不是的話(huà)會(huì)報(bào)語(yǔ)法錯(cuò)誤。當(dāng)執(zhí)行到return語(yǔ)句的時(shí)候,函數(shù)終止執(zhí)行,并返回expression的值給調(diào)用程序。例如:

代碼如下:

function square(x) {return x * x} //一個(gè)包含return的語(yǔ)句函數(shù)

square(4) //執(zhí)行為16

如果沒(méi)有return語(yǔ)句,則函數(shù)調(diào)用僅依次執(zhí)行函數(shù)體內(nèi)的每一條語(yǔ)句直到函數(shù)結(jié)束,最后返回調(diào)用程序。這種情況下,調(diào)用表達(dá)式的結(jié)果是undefined。return語(yǔ)句經(jīng)常作為函數(shù)內(nèi)最后的一條語(yǔ)句出現(xiàn),但并不是說(shuō)一定一定要放在函數(shù)的最后,即使在執(zhí)行return語(yǔ)句的時(shí)候還有很多代碼沒(méi)有執(zhí)行到,這時(shí)候函數(shù)也還返回調(diào)用程序。

return語(yǔ)句可以單獨(dú)使用而不必帶有expression,這樣的話(huà)函數(shù)也會(huì)想調(diào)用程序返回undefined.例如:

代碼如下:

//如果參數(shù)是null或者undefined則立即返回

if (!o) return;

//其它邏輯

由于javascript可以自動(dòng)插入分號(hào),因此,return關(guān)鍵字和它后面的表達(dá)式之間不能有換行。

iiiii.throw語(yǔ)句

所謂異常(excepion)是當(dāng)發(fā)生了某種異常情況或錯(cuò)誤時(shí)產(chǎn)生的一個(gè)信號(hào)。拋出異常,就是用信號(hào)通知發(fā)生了錯(cuò)誤或異常狀況。捕獲異常是指處理這個(gè)信號(hào),拋出異常,就是用信號(hào)通知發(fā)生了錯(cuò)誤或異常狀況。捕獲異常是指處理這個(gè)信號(hào),即采取必要的手段從異常中匯豐。在javascript中,當(dāng)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤或者程序使用throw語(yǔ)句時(shí)就會(huì)顯式的拋出異常。使用try/catch/finally語(yǔ)句可以捕獲異常,下一節(jié)會(huì)對(duì)它作詳細(xì)介紹。

throw語(yǔ)句的語(yǔ)法如下:

throw expression

expression的值可以是任意類(lèi)型的??梢?huà)伋鲆粋€(gè)代表錯(cuò)誤碼的數(shù)組,或者包含可錯(cuò)誤消息的字符串。當(dāng)javascript解釋器拋出異常的時(shí)候,通常采用Eeeor類(lèi)型或其子類(lèi)型,當(dāng)然也可以使用它們。一個(gè)error對(duì)象有一個(gè)那么熟悉表示錯(cuò)誤類(lèi)型,一個(gè)message屬性用來(lái)傳遞構(gòu)造函數(shù)的字符串(參照第三部分的Error類(lèi)),在下面的例子中,當(dāng)使用非法參數(shù)調(diào)用函數(shù)時(shí)就拋出一個(gè)Error對(duì)象:

代碼如下:

function fa(x) {

//如果輸入的參數(shù)是非法的,則拋出一個(gè)異常

if (x < 0) throw new Error("x不能是負(fù)數(shù)。");

//否則計(jì)算出一個(gè)值,正常地返回它

for (var f = 1; x > 1; f *= x, x--) /*empty*/;

return f;

}

當(dāng)拋出異常時(shí),javascript解釋器會(huì)立即停止當(dāng)前正在執(zhí)行的邏輯,并跳轉(zhuǎn)至就近的異常處理程序。異常處理程序用try/catch/finally語(yǔ)句的catch從句編寫(xiě)的。如果拋出的異常沒(méi)有一條關(guān)聯(lián)catch從句 ,解釋器會(huì)檢測(cè)更高層的閉合代碼塊,看它是否關(guān)聯(lián)相關(guān)的異常處理程序。以此類(lèi)推 ,直到扎到一個(gè)異常處理的程序?yàn)橹埂?/P>

如果拋出的異常函數(shù)沒(méi)有處理它的try/catch/finally語(yǔ)句,異常將向上傳播到調(diào)用該函數(shù)的代碼。這樣的話(huà),異常就會(huì)沿著javascript方法的詞法結(jié)構(gòu)和調(diào)用棧向上傳播。如果沒(méi)有找到任何異常處理的程序,javascript將吧異常當(dāng)成程序錯(cuò)誤來(lái)處理,并報(bào)告給用戶(hù)。

iiiiii.try/catch/finally語(yǔ)句

try/catch/finally語(yǔ)句是javascript的異常處理機(jī)制。其中try從句定義了需要處理的異常所在代碼塊。catch語(yǔ)句跟隨在try從句之后,當(dāng)try塊從某處發(fā)送了異常時(shí),調(diào)用了catch內(nèi)的代碼邏輯。catch從句跟隨finnlly塊,后者防置了清理代碼,不管try塊中是否產(chǎn)生了異常,finnally塊內(nèi)的邏輯總會(huì)執(zhí)行。盡管catch和finally都是可選的,但try從句只殺二者之一與組成完整的語(yǔ)句。try、catch和finally語(yǔ)句塊都需要花括號(hào)括起來(lái),這里的花括號(hào)是必須的。即使從句中只有一條語(yǔ)句也不能省略花括號(hào)。

下面的代碼說(shuō)明了try/catch/finlly的語(yǔ)法和使用目的:

代碼如下:

try{

//通常來(lái)講,這里的代碼會(huì)從頭執(zhí)行到尾而不會(huì)產(chǎn)生任何問(wèn)題,

//但有時(shí)會(huì)拋出一個(gè)異常,要么是由throw語(yǔ)句直接拋出異常

//要么通過(guò)調(diào)用一個(gè)方法間接拋出異常

}

catch(e){

//當(dāng)且僅當(dāng)try拋出了異常,才會(huì)執(zhí)行這里的代碼

//這里可以通過(guò)局部變量e來(lái)獲得對(duì)Error對(duì)象或者拋出的其它值的引用

//這里的代碼可以基于某種原因處理這個(gè)異常 ,也可以忽略這個(gè)異常。

//還可以通過(guò)throw語(yǔ)句重新拋出異常

}

finally{

//不管try語(yǔ)句塊是否拋出看異常,這里的邏輯總會(huì)執(zhí)行,終止try的語(yǔ)句塊方式有:

//1)正常終止,執(zhí)行完語(yǔ)句塊的最后一條語(yǔ)句

//2)通過(guò)break,continue或return語(yǔ)句終止

//3)拋出一個(gè)異常,異常被catch從句捕獲

//4)拋出一個(gè)異常,異常未被捕獲,繼續(xù)向上傳播

}

我們注意到,關(guān)鍵字catch后跟隨了一對(duì)圓括號(hào),圓括號(hào)內(nèi)是一個(gè)標(biāo)識(shí)符。這個(gè)標(biāo)識(shí)符和函數(shù)參很像。當(dāng)捕獲一個(gè)異常時(shí),把這個(gè)異常相關(guān)的值(比如Error對(duì)象)賦值給這個(gè)參數(shù)。和普通的變量不同,這條catch子句中的標(biāo)識(shí)符具有塊級(jí)作用域,它只在catch語(yǔ)句塊 內(nèi)有定義。

這里有一個(gè)關(guān)于try/catch語(yǔ)句更實(shí)際的例子,這里使用了前面章節(jié)中提到factorial()方法,并使用客戶(hù)端javascript方法prompt()和alert()來(lái)輸入和輸出

代碼如下:

try {

//要求用戶(hù)輸入一個(gè)數(shù)字

var n = Number(prompt("請(qǐng)輸入一個(gè)正整數(shù)", ""));

//假設(shè)輸入是合法的,計(jì)算這個(gè)階乘

var f = factorial(n);

//顯示結(jié)果

alert(n + "!=" + f);

} catch (ex) {

//如果輸入不合法,將執(zhí)行這里的邏輯

document.write(ex); //告訴用戶(hù)發(fā)送了什么。

}

這里的try/catch語(yǔ)句并不包含finally從句。盡管finally不像catch那樣經(jīng)常使用,但有時(shí)候它還是非常有用。然而,我們需要更詳盡的解釋它的行為。不管try語(yǔ)句塊中的代碼執(zhí)行完成了多少,只要try語(yǔ)句中有一部分代碼執(zhí)行了,finally從句就會(huì)執(zhí)行。它通常在try從句的代碼后用于清理工作。

關(guān)注下面這個(gè)例子

代碼如下:

try {

print("Outer try running..");

try {

print("Nested try running...");

throw "an error";

} catch (e) {

print("Nested catch caught " + e);

throw e + " re-thrown";

} finally {

print("Nested finally is running...");

}

} catch (e) {

print("Outer catch caught " + e);

} finally {

print("Outer finally running");

}

// Windows Script Host 作出該修改從而得出 WScript.Echo(s)

function print(s) {

document.write(s);

}

輸出:

代碼如下:

Outer try running..

Nested try running...

Nested catch caught an error

Nested finally is running...

Outer catch caught an error re-thrown

Outer finally running

7.其它語(yǔ)句類(lèi)型。

本節(jié)討論剩余的三種javascript語(yǔ)句:width,debugger和use strict

i.with語(yǔ)句

3.10討論了作用域鏈(scope chain),一個(gè)可以按序檢索的對(duì)象列表,通過(guò)它可以進(jìn)行變量名的解析。width語(yǔ)句可以用來(lái)臨時(shí)擴(kuò)展作用域鏈:它具體有如下語(yǔ)法:

with (object)

statement

這條語(yǔ)句將object添加到作用域鏈頭部,然后執(zhí)行statement,最后把作用域鏈恢復(fù)到原始狀態(tài)。

在嚴(yán)格模式下(5.7.iii)是禁止使用width的,在非嚴(yán)格模式下也是不推薦使用width語(yǔ)句的,盡可能的避免使用width語(yǔ)句。那些使用width語(yǔ)句的javascript非常難優(yōu)化,而且比沒(méi)有使用width的語(yǔ)句,它運(yùn)行速度更慢。

在對(duì)象嵌套層次很深的時(shí)候,常會(huì)使用with語(yǔ)句來(lái)簡(jiǎn)化代碼的編寫(xiě)。例如客戶(hù)端javascript中,可能使用下面的這種表達(dá)式來(lái)訪(fǎng)問(wèn)表單的一個(gè)html元素

document.forms[0].address.value

如果這段代碼多次出現(xiàn),則可以使用with將form對(duì)象添加至作用域鏈的頂層。

代碼如下:

with(document.forms[0]){

//直接訪(fǎng)問(wèn)表單元素

name.value="";

address.value="";

email.value ="";

}

這種方法簡(jiǎn)化了大量的輸入,不用再為每個(gè)變量添加document.forms[0]前綴。這個(gè)臨時(shí)對(duì)象掛載在作用域鏈上,當(dāng)javascript需要解析諸如address標(biāo)識(shí)符時(shí),就會(huì)在這個(gè)對(duì)象中查找。當(dāng)然,不使用with的語(yǔ)句代碼可以寫(xiě)成這樣。

代碼如下:

var f = document.forms[0];

f.name.value = "";

f.adress.value = "";

f.email.value = "";

不要忘記,只有在查找標(biāo)識(shí)符的時(shí)候才能用到作用域鏈,創(chuàng)建新的變量時(shí)候不使用它,看一下下面的代碼:

代碼如下:

with(o) x = 1;

如果對(duì)象o有一個(gè)屬性x,那么這行代碼給這個(gè)屬性賦值1。如果o沒(méi)有定義屬性x,這段代碼和不使用with的代碼x=1是一模一樣的。它給一個(gè)局部變量或者全局變量x賦值,或者創(chuàng)建全局對(duì)象的一個(gè)新屬性。with語(yǔ)句提供了一種讀取o屬性的快捷方法,但并不會(huì)創(chuàng)建o的屬性。

ii.debugger語(yǔ)句

debugger語(yǔ)句通常什么也不做。然而,在調(diào)試程序可用并運(yùn)行的時(shí)候,javascript解釋器將會(huì)(非必須)以調(diào)試模式運(yùn)行。實(shí)際上,這條語(yǔ)句產(chǎn)生一個(gè)斷點(diǎn)(breakpoint),javascript代碼執(zhí)行會(huì)停止在斷點(diǎn)的位置,這時(shí)可用使用調(diào)速器輸出變量的值,檢查調(diào)用棧等。

例如加上調(diào)用函數(shù)f()的時(shí)候使用了未定義的參數(shù),因此f()拋出一個(gè)異常,但無(wú)法定位到到底哪里出了異常。為了有助于調(diào)試這個(gè)問(wèn)題,需要修改f():

代碼如下:

function f(o){

if (o === undefined) debugger; //這段代碼用來(lái)臨時(shí)調(diào)試

console.log(1) //函數(shù)的其它部分

}

f();

這時(shí)候,當(dāng)調(diào)用f()沒(méi)有傳入?yún)?shù),程序?qū)⑼V箞?zhí)行,這時(shí)候通過(guò)調(diào)用調(diào)速器檢測(cè)調(diào)用棧并找出錯(cuò)誤的原因。

在ECMAScirpt5中,debugger語(yǔ)句已經(jīng)正式加入到專(zhuān)門(mén)語(yǔ)言里,但在很長(zhǎng)的一段時(shí)間里,主瀏覽器的廠(chǎng)商已經(jīng)將其實(shí)現(xiàn)了。注意,可用的調(diào)速器是遠(yuǎn)遠(yuǎn)不夠的,debugger語(yǔ)句不會(huì)啟動(dòng)調(diào)試器。但如果調(diào)試器已經(jīng)在運(yùn)行,這條語(yǔ)句才會(huì)正在產(chǎn)生斷點(diǎn)。例如,使用Firefox插件firebug,首先啟動(dòng)firebug,這樣debugger語(yǔ)句才能工作。

iii.“use strict”

“use strict”是ECMASCript5引入的一條指令。指令不是語(yǔ)句(但非常接近于語(yǔ)句),“use strict”和普通語(yǔ)句之前有兩個(gè)重要區(qū)別:

1.它不包含任何語(yǔ)言的關(guān)鍵字,指令僅僅是一個(gè)包含一個(gè)特殊字符串直接量的表達(dá)式(可以是使用單引號(hào)也可以是雙引號(hào))。

2.它只能出現(xiàn)在腳本代碼的開(kāi)始或者函數(shù)體的開(kāi)始、任何實(shí)體語(yǔ)句之前。但它不必一定出現(xiàn)在腳本的首行或者函數(shù)體內(nèi)的首行。因?yàn)椤皍se strict”指令之前之后或之前都可能有其它字符串直接量的表達(dá)式語(yǔ)句,并且javascript的具體實(shí)現(xiàn)可能將它們解析為解釋器自有的指令。在腳本或者函數(shù)體內(nèi)第一條常規(guī)語(yǔ)句之后,字符串直接量表達(dá)式語(yǔ)句只當(dāng)做普通的表達(dá)式語(yǔ)句對(duì)待,它們不做指令解析,它們也沒(méi)有任何副作用。

使用“use strict”指令的目的是說(shuō)明(腳本或函數(shù)中)后續(xù)代碼解析為嚴(yán)格代碼(strict code)。如果頂層(不在任何函數(shù)內(nèi))代碼使用了“use strict”指令,那么它們就是嚴(yán)格代碼。如果函數(shù)體定義處的代碼是嚴(yán)格代碼或者函數(shù)體使用了“use strict”指令,那么函數(shù)體的代碼也是嚴(yán)格代碼。如果eval()調(diào)用所處的代碼是嚴(yán)格代碼或者eval()要執(zhí)行的字符串使用了“scrict code”指令,則eval()內(nèi)的代碼是嚴(yán)格代碼。

嚴(yán)格代碼以嚴(yán)格模式執(zhí)行。ECMAScript5中的嚴(yán)格模式是該語(yǔ)言的一個(gè)受限的子集。它修正了語(yǔ)言的重要缺陷,并提供健壯的差錯(cuò)功能和增強(qiáng)安全機(jī)制。嚴(yán)格模式和非嚴(yán)格模式區(qū)別如下(前三條尤其重要)

•嚴(yán)格模式中禁止使用with語(yǔ)句

•嚴(yán)格模式中,所有的變量要先聲明,如果給一個(gè)未聲明的變量、函數(shù)、函數(shù)參數(shù)、catch從句參數(shù)或全局的對(duì)象的屬性賦值。就會(huì)拋出一個(gè)引用錯(cuò)誤異常(在非嚴(yán)格模式中,這種隱式聲明全局變量的方法是給全局變量新添加一個(gè)新屬性)

•嚴(yán)格模式中,調(diào)用的函數(shù)(不是方法)中的一個(gè)this值是undefined。(在非嚴(yán)格模式中,調(diào)用的函數(shù)中的this值總是全局變量)。可以利用這種特性來(lái)判斷javascript實(shí)現(xiàn)是否支持嚴(yán)格模式。

代碼如下:

var hasStrictMode = (function() {

"use strict";

return this === undefined

}());

•同樣,在嚴(yán)格模式中,當(dāng)通過(guò)call()和apply()來(lái)調(diào)用函數(shù)時(shí),其中的this值就是通過(guò)call()或apply()傳第一個(gè)參數(shù)(在非嚴(yán)格模式中,null和undefined值被全局對(duì)象轉(zhuǎn)換為對(duì)象的非對(duì)象值鎖代替)

•在嚴(yán)格模式中,給只讀屬性賦值和給不可擴(kuò)展的對(duì)象創(chuàng)建成員都將拋出一個(gè)類(lèi)型錯(cuò)誤異常(在非嚴(yán)格模式中,這些操作只是簡(jiǎn)單的操作失敗,不會(huì)報(bào)錯(cuò))。

•在嚴(yán)格模式中,傳入eval()代碼不能再調(diào)用辰星所在的上下文中聲明變量或定義函數(shù),在非嚴(yán)格模式中是可以這樣做的。相反,變量和函數(shù)的定義是在eval()創(chuàng)建的作用域中,這個(gè)作用域在eval()返回時(shí)就棄用了。

•在嚴(yán)格模式中,函數(shù)里的arguments對(duì)象擁有傳入函數(shù)值的靜態(tài)副本。在非嚴(yán)格模式中,agreements對(duì)象具有“魔術(shù)般”的行為,arguments里的數(shù)組元素和函數(shù)都指向同一個(gè)值的引用。

•在嚴(yán)格模式中,當(dāng)delete運(yùn)算符后面跟隨非法的標(biāo)識(shí)符(比如變量、函數(shù)、函數(shù)參數(shù)時(shí))將會(huì)拋出一個(gè)語(yǔ)法錯(cuò)誤,(在非嚴(yán)格模式下,這種delete什么也沒(méi)做,并返回false)

•在嚴(yán)格模式中,在一對(duì)象直接量中定義兩個(gè)或多個(gè)同名屬性將產(chǎn)生一個(gè)語(yǔ)法錯(cuò)誤(非嚴(yán)格模式下不會(huì)報(bào)錯(cuò))

•在嚴(yán)格模式下,不允許八進(jìn)制整數(shù)直接量。(以0為前綴,而不是0x為前綴)在非嚴(yán)格模式中是允許直接八進(jìn)制直接量的

•在嚴(yán)格模式下,標(biāo)識(shí)符eval和arguments當(dāng)做關(guān)鍵字,他們的值是不能更改的。不能給這些標(biāo)識(shí)符賦值,也不能把它們聲望為變量,用做函數(shù)名,用做函數(shù)參數(shù)或用做catch塊的標(biāo)識(shí)符。

•在嚴(yán)格模式中限制了對(duì)調(diào)用棧的檢測(cè)能力,在嚴(yán)格的模式的函數(shù)中,arguments,caller和arguments.callee都會(huì)拋出一個(gè)類(lèi)型錯(cuò)誤異常。嚴(yán)格模式的函數(shù)同樣具有caller和arguments屬性,當(dāng)訪(fǎng)問(wèn)這兩個(gè)屬性時(shí)拋出類(lèi)型錯(cuò)誤異常。

8.javascript語(yǔ)句小結(jié):

javascript語(yǔ)句語(yǔ)法:

語(yǔ)句語(yǔ)法用途

breakbreak[label];退出最內(nèi)側(cè)循環(huán)或者退出switch語(yǔ)句,又或退出label指定的語(yǔ)句

casecase expression:在switch語(yǔ)句標(biāo)記一條語(yǔ)句

continuecontinue [label];重新開(kāi)始最內(nèi)層的循環(huán)或從新開(kāi)始label指定的循環(huán)

debuggerdebugger;斷點(diǎn)器調(diào)試

defaultdefault;在switch標(biāo)記默認(rèn)語(yǔ)句

do/whiledo statement while(expression);while循環(huán)的一種替代形式

empty;什么都不做

forfor(init;test;incr)statement一種簡(jiǎn)寫(xiě)的循環(huán)

for/infor(var in object)statement遍歷一個(gè)對(duì)象屬性

functionfunction name([param[],...]){body}聲明一個(gè)函數(shù)

if/elseif (expr)statement1[else statement2]執(zhí)行statement1或者statement2

labellabel:statement給statement指定一個(gè)名字:label

returnreturn [expression];從函數(shù)返回一個(gè)值

switchswitch(expression){statements}用case或者“default:”語(yǔ)句標(biāo)記多個(gè)分支語(yǔ)句

throwthrow expression拋出異常

trytry {statements}

[catch {hander satements}]

[finally {cleanup satements}]捕獲異常

use strict"use strict"對(duì)腳本和函數(shù)使用嚴(yán)格模式

varavr name=[=expr][,...]聲明并初始化一個(gè)或多個(gè)變量

whilewhile (expression) statement基本的循環(huán)結(jié)構(gòu)

withwith(object) statement擴(kuò)展作用域鏈(不贊成使用)

更多信息請(qǐng)查看IT技術(shù)專(zhuān)欄

更多信息請(qǐng)查看腳本欄目
易賢網(wǎng)手機(jī)網(wǎng)站地址:Javascript核心讀書(shū)有感之語(yǔ)句
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢(xún)回復(fù)僅供參考,敬請(qǐng)考生以權(quán)威部門(mén)公布的正式信息和咨詢(xún)?yōu)闇?zhǔn)!

2025國(guó)考·省考課程試聽(tīng)報(bào)名

  • 報(bào)班類(lèi)型
  • 姓名
  • 手機(jī)號(hào)
  • 驗(yàn)證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡(jiǎn)要咨詢(xún) | 簡(jiǎn)要咨詢(xún)須知 | 新媒體/短視頻平臺(tái) | 手機(jī)站點(diǎn) | 投訴建議
工業(yè)和信息化部備案號(hào):滇ICP備2023014141號(hào)-1 云南省教育廳備案號(hào):云教ICP備0901021 滇公網(wǎng)安備53010202001879號(hào) 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號(hào)
云南網(wǎng)警備案專(zhuān)用圖標(biāo)
聯(lián)系電話(huà):0871-65099533/13759567129 獲取招聘考試信息及咨詢(xún)關(guān)注公眾號(hào):hfpxwx
咨詢(xún)QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)
云南網(wǎng)警報(bào)警專(zhuān)用圖標(biāo)