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

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

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

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

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

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

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

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

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

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

1.表達(dá)式語句

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

代碼如下:

greet = "hello" + name;

i *= 3;

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

代碼如下:

counter++;

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

代碼如下:

delete o.x;

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

代碼如下:

alert(greet);

window.close();

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

Math.cos(x);

相反,得出余弦值就得把它賦值給一個變量,以便將來使用這個值:

var cx = Math.cos(x);

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

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

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

代碼如下:

{

x = Math.PI;

cx = Math.cos(x);

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

}

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

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

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

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

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

;//分號

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

代碼如下:

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

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

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

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

代碼如下:

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

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

如果有特殊目的使用空語句,最好在代碼中添加注釋,這樣能更清楚的說明這條空語句是有用的

代碼如下:

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

3.聲明語句

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

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

i.var

var語句用來聲明一個或者多個變量,它的語法如下:

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

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

代碼如下:

var i; //一個簡單的變量

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

var p, q; //兩個變量

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

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

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

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

代碼如下:

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);

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

ii.function

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

代碼如下:

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

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

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

代碼如下:

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

statements

}

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

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

代碼如下:

function hyteus(x, y) {

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

}

hyteus(1, 2) //=>2.23606797749979

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

if (n <= 1) return 1;

return n * facial(n - 1);

}

facial(11) //=>39916800

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

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

4.條件語句

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

i.if語句

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

代碼如下:

if (expression)

statement

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

代碼如下:

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

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

需要注意的是,if語句括住expression的園括號是必須的。

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

代碼如下:

if (!address) {

address = "";

message = "please mailing address"

}

if語句的第二種形式引入了else從句,當(dāng)expression的值是false值時執(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語句中,嵌套使用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"); //錯誤!!

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

代碼如下:

if (i == j) {

if (j == k)

console.log("i equs k");

else

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

}

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

代碼如下:

if (i == j) {

if (j == k) {

console.log("i equs k");

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

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

}

}

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

ii.else if

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

代碼如下:

if (n == 1) {

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

} else if (n == 2) {

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

} else if (n == 3) {

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

} else {

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

}

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

iii.switch

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

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

代碼如下:

switch (expression) {

statements

}

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

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

switch語句是非常容易混淆的,用例子介紹會比較清晰一點,下面的switch語句和方才的if/else語句是等價的

代碼如下:

switch (n) {

case 1: //如果n ===1從這里開始

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

break;

case 2:

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

break;

case 3:

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

break;

default:

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

break;

}

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

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

代碼如下:

function convert(x) {

switch (typeof x) {

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

return x.toString(16);

case 'string':

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

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

return String(x);

}

}

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

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

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

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

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

5.循環(huán)。

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

i.while

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

代碼如下:

while (expression)

statement

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

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

代碼如下:

var count = 0;

while (count < 10) {

console.log(count);

count++;

}

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

ii.do/while

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

代碼如下:

do

statement

while(expression);

do/while循環(huán)并不像while循環(huán)那么常用。這是因為在實踐中想要循環(huán)至少執(zhí)行一次的情況并不常見。下面是一個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)之間有兩點語法方面的不同之處。首先,do循環(huán)要求必須使用關(guān)鍵字do來標(biāo)識循環(huán)的開始,用while變標(biāo)識循環(huán)的結(jié)尾并進(jìn)入循環(huán)條件判斷;其次,和while循環(huán)不同,do循環(huán)使用分號結(jié)尾的。如果while的循環(huán)體使用花括號括起來,則while循環(huán)也不使用分號結(jié)尾。

iii.for

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

代碼如下:

for (initialize; test; increment)

statement

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

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

代碼如下:

initialize

while (test) {

statement

increment;

}

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

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

代碼如下:

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

console.log(count)

當(dāng)然,有些循環(huán)更加復(fù)雜,而且循環(huán)中一次迭代多個變量。在javascript,這種情況必須用到逗號運算符,它將初始化表達(dá)式和自增表達(dá)式合并入一個表達(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)來遍歷表數(shù)據(jù)結(jié)果,并返回鏈表中最后一個對象(也就是第一個不包含next屬性的對象)

代碼如下:

function tail(o) { //返回鏈表的最后一個節(jié)點對象

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

return o;

}

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

iiii.for/in

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

代碼如下:

for (variable in object)

statement

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

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

代碼如下:

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

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

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

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

代碼如下:

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

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

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

需要注意的是,只要for/in循環(huán)中,varibale的值可以當(dāng)做賦值表達(dá)式的左值,它可以是任意表達(dá)式。每次循環(huán)都會計算這個表達(dá)式,也就是說每次循環(huán)它計算的值可能不同。例如,可以使用下面的這段代碼將所有對象屬性復(fù)制到一個數(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ù)組只不過是一種特殊的對象,因此,for/in循環(huán)可以像枚舉對象屬性一樣枚舉數(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將對象屬性復(fù)制到一個數(shù)組中

for(i in a)

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

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

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

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

屬性枚舉的順序

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

1.對象繼承了可枚舉屬性

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

3.使用delete刪除了對象已有的屬性

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

6.跳轉(zhuǎn)

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

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

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

接下來,描述每一種跳轉(zhuǎn)語句

i.標(biāo)簽語句

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

identifier:statement

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

代碼如下:

mainloop: while (token != null) {

//忽略這里代碼...

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

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

}

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

ii.break

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

break;

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

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

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

代碼如下:

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

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

}

javascript中同樣允許break關(guān)鍵字后跟隨一個語句標(biāo)簽,(只有標(biāo)識符,沒有冒號)

break labelname;

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

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

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

代碼如下:

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

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

var sum = 0,

success = false;

//從簽名處開始,以便在報錯時推出程序。

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語句跳轉(zhuǎn)至此

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

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

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

iii.continue語句

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

continue;

continue語句會也會帶有標(biāo)簽

continue lebname;

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

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

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

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

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

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

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

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

代碼如下:

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

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

total += data[i];

}

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

iiii.return

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

return expression;

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

代碼如下:

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

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

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

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

代碼如下:

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

if (!o) return;

//其它邏輯

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

iiiii.throw語句

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

throw語句的語法如下:

throw expression

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

代碼如下:

function fa(x) {

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

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

//否則計算出一個值,正常地返回它

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

return f;

}

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

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

iiiiii.try/catch/finally語句

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

下面的代碼說明了try/catch/finlly的語法和使用目的:

代碼如下:

try{

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

//但有時會拋出一個異常,要么是由throw語句直接拋出異常

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

}

catch(e){

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

//這里可以通過局部變量e來獲得對Error對象或者拋出的其它值的引用

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

//還可以通過throw語句重新拋出異常

}

finally{

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

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

//2)通過break,continue或return語句終止

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

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

}

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

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

代碼如下:

try {

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

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

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

var f = factorial(n);

//顯示結(jié)果

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

} catch (ex) {

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

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

}

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

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

代碼如下:

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.其它語句類型。

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

i.with語句

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

with (object)

statement

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

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

在對象嵌套層次很深的時候,常會使用with語句來簡化代碼的編寫。例如客戶端javascript中,可能使用下面的這種表達(dá)式來訪問表單的一個html元素

document.forms[0].address.value

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

代碼如下:

with(document.forms[0]){

//直接訪問表單元素

name.value="";

address.value="";

email.value ="";

}

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

代碼如下:

var f = document.forms[0];

f.name.value = "";

f.adress.value = "";

f.email.value = "";

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

代碼如下:

with(o) x = 1;

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

ii.debugger語句

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

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

代碼如下:

function f(o){

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

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

}

f();

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

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

iii.“use strict”

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

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

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

使用“use strict”指令的目的是說明(腳本或函數(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)格模式是該語言的一個受限的子集。它修正了語言的重要缺陷,并提供健壯的差錯功能和增強(qiáng)安全機(jī)制。嚴(yán)格模式和非嚴(yán)格模式區(qū)別如下(前三條尤其重要)

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

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

•嚴(yán)格模式中,調(diào)用的函數(shù)(不是方法)中的一個this值是undefined。(在非嚴(yán)格模式中,調(diào)用的函數(shù)中的this值總是全局變量)??梢岳眠@種特性來判斷javascript實現(xiàn)是否支持嚴(yán)格模式。

代碼如下:

var hasStrictMode = (function() {

"use strict";

return this === undefined

}());

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

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

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

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

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

•在嚴(yán)格模式中,在一對象直接量中定義兩個或多個同名屬性將產(chǎn)生一個語法錯誤(非嚴(yán)格模式下不會報錯)

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

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

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

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

javascript語句語法:

語句語法用途

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

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

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

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

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

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

empty;什么都不做

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

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

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

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

labellabel:statement給statement指定一個名字:label

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

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

throwthrow expression拋出異常

trytry {statements}

[catch {hander satements}]

[finally {cleanup satements}]捕獲異常

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

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

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

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

更多信息請查看IT技術(shù)專欄

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

2025國考·省考課程試聽報名

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