摘要:每個(gè)候選項(xiàng)都是大括號中的語句序列。短路運(yùn)算符有一個(gè)很重要的功能它們并不真的需要布爾值操作數(shù),注意換句話說,不會(huì)將數(shù)字轉(zhuǎn)換為布爾值。練習(xí)對表達(dá)式求值。首先對求值,轉(zhuǎn)換為繼續(xù)對右邊表達(dá)式求值,為,造成短路,不對進(jìn)行計(jì)算,返回對表達(dá)式求值。
4.1 聲明語句
聲明語句也叫變量語句,這種語句會(huì)創(chuàng)建新變量??梢栽诼暶髯兞繒r(shí)給出初始值,如果沒有明確給出,變量的值就是undefined。
var count = 0; var dogs = ["Sparky","Spot","Spike"]; var response; var melta = {latitude:35.8,longitude:14.6}; var finished = false; var winner = null;
這段腳本明確給出了幾個(gè)變量的初始值,事實(shí)上,除response之外都有了初始值。這時(shí)候,變量response的值就是undefined。
可以在一個(gè)語句中聲明多個(gè)變量,可以給部分變量賦初始值。
var start = 0,finish = 72,input,output = [];
這個(gè)語句會(huì)將input初始化為undefined值。
4.2 表達(dá)式語句表達(dá)式語句對表達(dá)式求值但,忽略得到的值。這聽起來有點(diǎn)傻,因?yàn)榭梢跃帉懗鲱愃朴谙旅娴臒o用腳本;
2+2; // 計(jì)算2+2,僅此而已 "hello"; // 也有效,但完全沒用 Math.sqrt(100); // 完成計(jì)算,也僅此而已 "a".toLowerCase(); // 得到一個(gè)新字符串,但忽略它
但是可以借助表達(dá)式的副作用來創(chuàng)建有用的語句,所謂"副作用",就是一些操作,可以生成可見結(jié)果、改變變量或?qū)ο髮傩灾斜4娴闹?,或者修改對象的結(jié)構(gòu)等。之前的delete運(yùn)算符與alert和賦值一樣,都會(huì)產(chǎn)生副作用
var x = 2; // 聲明x,初始化為2 alert(x); // 顯示2 alert(10*x); // 顯示20 var y; // 聲明y,但不明確賦值 alert(y); // 顯示undefined
記住,變量聲明和賦值就是簡單地把一個(gè)值放到一個(gè)變量里,僅此而已。除此之外,沒有任何其他后果,比如不會(huì)設(shè)定變量與變量之間的關(guān)系。在前面的腳本中,聲明var z = y不會(huì)讓z和y成為同一個(gè)變量,也不會(huì)要求它們在之后始保存相同的值。這個(gè)語句意思僅僅是"新建一個(gè)變量z,讓它的初始值等于y的當(dāng)前值"。之后再給y重新賦一個(gè)新值時(shí),z的值不會(huì)變。
4.3 條件執(zhí)行JavaScript提供了一些語句和幾個(gè)運(yùn)算符,可以讓我們編寫的腳本在特定條件下執(zhí)行一操作,在不同條件下則執(zhí)行另一組操作。
4.3.1 if語句if語句會(huì)根據(jù)你提供的條件,最多執(zhí)行許多候選操作中的一種。這個(gè)語句的最一般形式是有一個(gè)if部分,0個(gè)或多個(gè)else if部分,還可根據(jù)需要帶有else部分。每個(gè)候選項(xiàng)都是大括號中的語句序列。這些條件會(huì)自上而下一次評估。只要一個(gè)條件為真,就會(huì)執(zhí)行它對應(yīng)的候選操作,然后結(jié)束整個(gè)if語句。
var score = Math.round(Math.random()*100); if (score>=90) { grade = "A"; } else if (score>=80) { grade = "B"; } else if (score>=70) { grade = "C"; } else if (score>=60) { grade = "D"; } else { grade = "F"; }; alert(score+" is a "+grade)
下圖用一種UMKL(Unified Modeling Language,統(tǒng)一建模語言)活動(dòng)圖解讀了上述語句。UML是一種非常流行的軟件系統(tǒng)可視化語言。這張圖傳達(dá)的事實(shí)就是:會(huì)逐個(gè)檢測每個(gè)條件,一旦發(fā)現(xiàn)一個(gè)條件成立,就不再進(jìn)行測試。
編寫一個(gè)if語句,當(dāng)變量s沒有包含長度為16的字符串時(shí),提示一條消息(注意,這個(gè)語句沒有else if或else部分)
var s = prompt("Enter a something"); if (s.length!==16) { alert("string length isn"t 16") };
編寫一個(gè)if語句,檢查變量x的值,(1)如果x>0,則將它加到數(shù)組變量values的末尾;(2)如果x<0,則將它加到values的前面;(3)如果x===0,則遞增變量zeroCount;(4)柔則,什么也不做。
var values = []; var zeroCount = 0; var x = Number(prompt("Enter a number")); if (x>0) { values.push(x); } else if (x<0) { values.unshift(x); } else if (x===0) { zeroCount++; };4.3.2 ?:條件表達(dá)式
有時(shí)你可能更喜歡使用條件表達(dá)式,而不是if語句。條件表達(dá)式就是"x?y:z",當(dāng)x為真時(shí),表達(dá)式的結(jié)果為y,當(dāng)x為假時(shí),表達(dá)式的結(jié)果為z。
if (latitude>=0) { hemisphere = "north"; } else { hemisphere = "south"; } // 寫為: hemisphere = (latitude>=0) ? "north" : "south";
條件表達(dá)式有時(shí)會(huì)用在構(gòu)建字符串的表達(dá)式中,如下(這里的present假定是一個(gè)保存布爾值的變量:)
var notice = "She is "+(present? "" : "n"t")+" here.";4.3.3 switch語句
另一種條件語句 —— switch語句,將一個(gè)值一系列case進(jìn)行比較,知道找出一個(gè)與它的值相等(===)的case,然后從該處開始執(zhí)行語句??梢愿鶕?jù)需要包含一個(gè)default case,它會(huì)匹配所有值。
switch (direction.toLowerCase()){ case "north" : row -= 1; break; case "south" : row += 1; break; case "east" : column += 1; break; case "west" : column -= 1; break; default: alert("Illegal direction"); }
break語句會(huì)終止整個(gè)switch語句。每種case都以一個(gè)break結(jié)束,這是一種很好的做法;否則,執(zhí)行會(huì)"直落"到下一個(gè)case(不會(huì)再與剩下的case表達(dá)式進(jìn)行比較)。例如,上面的腳本我們省略了break,而且方向是"east",會(huì)發(fā)生什么情況呢?column中的值會(huì)被遞增,然后遞減,然后彈出一個(gè)提示框,告訴你"east"不是一個(gè)合法方向。
有時(shí),"直落"正是我們想要的。假定在一群參加競賽的人中,每個(gè)人都獲得一個(gè)證書,但達(dá)到一級獎(jiǎng)勵(lì)的人還會(huì)得到一個(gè)背包,達(dá)到二級獎(jiǎng)勵(lì)的人還會(huì)得到一次滑雪度假,而達(dá)到三級獎(jiǎng)勵(lì)的人還會(huì)獎(jiǎng)勵(lì)一倆汽車。這種情況就可以使用沒有break語句的編碼。
/* * 這個(gè)腳本會(huì)為一個(gè)給定獎(jiǎng)勵(lì)級別生別一組獎(jiǎng)勵(lì) * 每個(gè)獎(jiǎng)勵(lì)級別的參賽者會(huì)得到該級獎(jiǎng)勵(lì)和所有 * 低級獎(jiǎng)勵(lì)。它使用了一種很丑陋的switch語句 * 形式,其中的各個(gè)case之間沒有相互距離。 */ var level = +prompt("Enter your prize level,1-3"); var prizes = []; switch (level){ case 3 : prizes.push("car"); case 2 : prizes.push("ski vacation"); case 1 : prizes.push("backpack"); default: prizes.push("certificate"); } alert(prizes);
一個(gè)具有直落效果的switch語句的活動(dòng)圖
像這樣的計(jì)算很少會(huì)在現(xiàn)實(shí)中發(fā)生所以一般來說,還是避免使用那些不以break(或其他某一中斷語句)結(jié)束的case,以防與switch更常見的形式混淆。事實(shí)上,之前介紹的JSLint代碼質(zhì)量檢查工具就是將"直落"看作錯(cuò)誤!我們總能為直落switch找出替代方法。
4.3.4 用查詢避免條件代碼來看一種情景,至少對于許多程序員新手來說,這種情景似乎是需要使用if語句,?:運(yùn)算符或者switch語句。假定有一個(gè)變量state,保存德國一個(gè)州名,我們希望將這個(gè)州的首府名賦值給變量capital,如果不能識別州名,則為其賦值undefined。
// 丑陋的代碼 —— 不要使用這一代碼 if (state === "Baden-Wurttemberg") { capital = "Strttgart"; } else if (state = "Bayern") { capital = "Munchen"; } else if (state = "Berlin") { capital = "Berlin"; } else if (state = "Potsdam") { capital = "Potsdam"; } else if (state = "Bremen") { capital = "Bremen"; } else if (state = "Hamburg") { capital = "Hessen"; } else { capital = undefined; }
此代碼對每個(gè)州都重復(fù)兩段內(nèi)容:state === 和 capital = 。switch語句可以消除前者,但必須為每個(gè)州都增加一個(gè)break —— 沒有實(shí)質(zhì)性的改進(jìn)。
// 丑陋的代碼 —— 不要使用這一代碼 switch (state){ case "Baden-Wurttemberg" : capital = "Stuttgart"; break; case "Bayern" : capital = "Munchen"; break; case "Berlin" : capital = "Berlin"; break; case "Brandenburg" : capital = "Potsdam"; break; case "Bremen" : capital = "Bremen"; break; case "Hamburg" : capital = "Hambrug"; break; case "Hessen" : capital = "Wiesbaden" break; default:capital = undefined; }
我們將在第三次嘗試中使用的條件表達(dá)式可以消除賦值的重復(fù)作用,但無法消除相等檢測中的重復(fù)。
capital = (state === "Baden-Wurttemberg") ? "Stuttgart" : (state === "Bayern") ? "Munchen" : (state === "Berlin") ? "Berlin" : (state === "Brandenburg") ? "Potsdam" : (state === "Bremen") ? "Bremen" : (state === "Hamburg") ? "Hamburg" : (state === "Hessen") ? "Wiesbaden" : undefined;
我們不能將所有重復(fù)片段排除在外,這一定意味著存在一種更好的方法來查找首府,事實(shí)上也的確存在。如果剔除了所有關(guān)于測試與賦值的內(nèi)容,還剩下什么呢?就是州和首府!我們并不需要什么精確的計(jì)算來將州和首府關(guān)聯(lián)在一起,可以在數(shù)據(jù)而非代碼中定義這種關(guān)系。我們所需要的就是一個(gè)簡單對象。
var CAPITALS = { "Baden-Wurttemberg" : "Stuttgart", "Bayern" : "Munchen", "Brandenburg" : "Potsdam", "Bremen" : "Bremen", "Hamburg" : "Hamburg", "Hessen" : "Wiesbaden" };
現(xiàn)在,只需寫出:
capital = CAPITALS[state];
就能獲得變量state中所包含州的首府??梢哉J(rèn)為這一代碼是在一個(gè)由州及首府組成的表格中查詢首府。在這樣使用一個(gè)對象時(shí),就說它是一個(gè)查詢表、一個(gè)詞典、一個(gè)映射、一個(gè)關(guān)聯(lián)數(shù)組、或一個(gè)數(shù)列。查詢表通常是將鍵映射到值(key = value)。這里的州是鍵,首府是值。在適用時(shí),查詢代碼要優(yōu)于條件代碼,原因有如下幾個(gè)。
沒有冗余的代碼片段,是腳本更短、更易于理解。
州和首府的顯示位置緊挨在一起,更容易"看出"它們之間的關(guān)聯(lián)。
代碼(查詢)和數(shù)據(jù)(查詢表)在本質(zhì)上是不同的東西,不應(yīng)當(dāng)混放在一起。
JavaScript引擎執(zhí)行查詢的速度要遠(yuǎn)快與條件代碼。
還有一個(gè)例子,我們使用詞典來關(guān)聯(lián)手機(jī)鍵盤上的數(shù)字和字母。
為了將帶有字母的電話號碼轉(zhuǎn)換為號碼,我們可以使用:
var LETTER_TO_NUMBER = { A:2, B:2, C:2, D:3, E:3, F:3, G:4, H:4, I:4, J:5, K:5, L:5, M:6, N:6, O:6, P:7, Q:7, R:7, S:7, T:8, U:8, V:8, W:9, X:9, Y:9, Z:9 };
比如LETTER TO NUMBER["C"] === 2。能不能在另一個(gè)方向上使用這個(gè)映射呢?單個(gè)數(shù)字可以映射為多個(gè)字母,所以我們將使用字符串:
var NUMBER_TO_LETTER = { 2:"ABC", 3:"DEF", 4:"GHI", 5:"JKL", 6:"MNO", 7:"PQRS", 8:"TUV", 9:"WXYZ" };
這里,我們說:“給定一個(gè)數(shù)字n,NUMBER TO LETTER[n]”的值是一個(gè)字符串,其中包含了與鍵盤上的n相關(guān)聯(lián)的所有字母(而且也只有這些字母)?!痹诤罄m(xù)介紹處理整個(gè)手機(jī)號碼腳本時(shí)間,將會(huì)用到這些詞典中的第一個(gè)。
練習(xí)
用你自己的語言,說明可以用查詢代替條件代碼結(jié)構(gòu)的情景(為之前的分?jǐn)?shù)與成績示例使用查詢策略)
var score = { 100:"A", 99:"A", 98:"A", 80:"B", 85:"B", 89:"B", }; alert(score[100])
情景:查詢電話歸屬地、郵編。元素周期表......
假定你注意到某一代碼中存在表達(dá)式CAPITALS[Saarland]。幾乎可以肯定它有什么錯(cuò)誤?
可能存在語法錯(cuò)誤,方括號運(yùn)算符中如果不是變量,必須用引號括起
4.3.5 短路執(zhí)行之前的布爾值一章中,如果x和y都是布爾值,則AND-ALSO和OR-ELSE運(yùn)算符具有以下特性:
當(dāng)且僅當(dāng)x或y為真(或均為假)時(shí),x || y為真
當(dāng)且僅當(dāng)x和y均為真時(shí),x && y為真
if (t<0 && t>100) { /**執(zhí)行某些操作**/ } // 與下面代碼的含義完全相同 if (t<0) { if (t>100) { /**執(zhí)行某些操作**/ } }
如果第一部分的求值已經(jīng)獲得了足夠多的信息,那就講第二部分的求值短路,也就是跳過。
我們現(xiàn)在明白AND-ALSO和OR-ELSE名字的緣由了。
x and also y就是說:若(if)x為真,則(then)(且僅在此時(shí))去查看y是否也(also)為真。
x or else y 就是說:若(if)x為真,那很好;否則(else)必須去查看y是否為真。
第二部分根據(jù)條件決定是否求值。
短路運(yùn)算符有一個(gè)很重要的功能:它們并不真的需要布爾值操作數(shù),注意:alert(27 && 52); // 52 alert(0 && 52); // 0 alert(27 || 52); // 27 alert(0 || 52); // 52
換句話說,JavaScript不會(huì)將數(shù)字轉(zhuǎn)換為布爾值。
為計(jì)算x && y的值,JavaScript首先對x求值。如果x為假(false或可以轉(zhuǎn)換為false),則整個(gè)表達(dá)式得出x的值(不再計(jì)算y)。否則整個(gè)表達(dá)式得出y的值。
為計(jì)算x || y的值,JavaScript首先對x求值。如果x為真(true或可以轉(zhuǎn)換為true),則整個(gè)表達(dá)式得出x的值(不再計(jì)算y)。否則,整個(gè)表達(dá)式得出y的值。
利用這一行為,可以編寫一些小巧的代碼。假定有一個(gè)變量favoriteColor,我們知道,如果你有最喜歡的顏色,這個(gè)變量就包含了這種顏色的名稱,如果沒有最愛的顏色,那它的值就是undefined。如果有喜歡的顏色,就用這種顏色為汽車噴漆,如果沒有,則噴為黑色;
car.color = favoriteColor || "black";
這一行代碼是有效的,因?yàn)?b>favoriteColor中包含了一個(gè)非空字符串,它為真,所以會(huì)為其指定car的顏色。如果favoriteColor為undefined(為假),則根據(jù)定義,||表達(dá)式的值就是它的第二個(gè)(右側(cè))操作數(shù),也就是黑色。
練習(xí)
對表達(dá)式 3 && "xyz" || null求值。
首先對3 && "xyz"求值,3轉(zhuǎn)換為true,繼續(xù)對右邊表達(dá)式求值,為true,造成 ||短路,不對null進(jìn)行計(jì)算,返回"xyz"
對表達(dá)式3 && "" || null求值。
首先對3 && ""求值計(jì)算,空字符串轉(zhuǎn)換為false,而因||需要,繼續(xù)對右邊表達(dá)式求值,返回null
判斷正誤:對于變量x和y,x && y總是等同于x ? y : x
正確
首先對x求值,判斷是否短路,x為真,求值y,x為假,那只有x已求值
判斷正誤:對于變量x和y,x || y總是等同于x ? x : y、
正確
首先對x求值,判斷是否短路,x為真,短路并返回,x為假,繼續(xù)求值y
4.4 迭代上一節(jié)研究了不同情況下做不同事情的方法?,F(xiàn)在來看一遍又一遍地重復(fù)同一事情的方法。
4.4.1 while和do-while語句JavaScript的while語句會(huì)在條件為真時(shí)重復(fù)執(zhí)行代碼。下面的例子要求用戶輸入一個(gè)恰有五個(gè)字符的字符串,并一直詢問,知道用戶遵守指令為止。當(dāng)用戶輸入不滿足要求時(shí),腳本會(huì)計(jì)算嘗試次數(shù)(并重復(fù)提示)。只有在輸入了可接受的字符串時(shí),while語句才會(huì)結(jié)束。
var numberOfTries = 1; while (prompt("Enter a 5-charater string").length !== 5){ numberOfTries += 1; } if (numberOfTries>1) { alert("Took you "+numberOfTries+" tries to get this right"); }
while語句的一般形式為:
while (test) { stmts }
首先執(zhí)行第一個(gè)test,如果它為真,則執(zhí)行循環(huán)體,重復(fù)整個(gè)語句。這就是說,條件測試出現(xiàn)在循環(huán)體之前,循環(huán)體可能一次也不會(huì)執(zhí)行。而在do-while語句中國,循環(huán)體至少會(huì)執(zhí)行一次。一般形式為:
do {stmts} while (test)
可以用do-while語句重寫以上腳本:
var numberOfTries = 0; do { var input = prompt("Enter a 5-character string"); numberOfTries++; } while (input.length!==5); if (numberOfTries>1) { alert("Took you "+numberOfTries+" tries to get this right"); }4.2.2 for語句
第二種循環(huán) —— for語句,也就是在條件為真時(shí)一直循環(huán),但它通常用于迭代遍歷一個(gè)固定的項(xiàng)目集,比如一個(gè)數(shù)值范圍、一個(gè)字符串中的字符、一個(gè)數(shù)組的索引、一個(gè)對象鏈,等等。這個(gè)語句一般形式是:
for (init ; test ; each) {stmts}
JavaScript引擎首先運(yùn)行init代碼,然后,只要test為真,則運(yùn)行循環(huán)體,然后運(yùn)行each。init部分通常會(huì)聲明一或多個(gè)變量(但并非總是如此)。
// 顯示4,6,8,10,...,20為偶數(shù) for (var Number=4;Number<=20;Number+=2) { alert(Number+" is even ") }
這里number被初始化為4,而且因?yàn)樗∮诘扔?0,所以將提示"4 is even",然后將number直接設(shè)置為6,接下來將顯示"6 is even",number變?yōu)?。最后顯示20,因?yàn)樽詈髇umber將跳到22,條件為false。
在處理數(shù)組時(shí)會(huì)使用for語句。下面例子中,處理一個(gè)單詞列表,也就是字符串words[0]、words[1]、words[2],等等。如何"逐步遍歷"這個(gè)列表呢?可以創(chuàng)建一個(gè)變量i,它會(huì)在每次的迭代中遞增1.
// 顯示一個(gè)字符串,又每個(gè)數(shù)組項(xiàng)目的首個(gè)字母組成 var words = ["as","far","as","i","know"]; var result = ""; for (var i=0;i下面是一個(gè)另一個(gè)與數(shù)組有關(guān)的例子,它演示了一種常見模式,用于檢查每個(gè)數(shù)組元素,看它是否滿足某一條件。 // 顯示一個(gè)數(shù)組中的0的個(gè)數(shù)
var a = [7,3,0,0,9,-5,2,1,0,1,7]; var numberOfZeros = 0; for (var i=0,n=a.length;i注意這個(gè)示例還演示了如何在for循環(huán)的初始化部分聲明兩個(gè)變量。將n初始化為數(shù)組的長度,循環(huán)終止檢測變得簡單一點(diǎn)。
除了迭代數(shù)值范圍和數(shù)組元素之外,for語句還經(jīng)常用于迭代一個(gè)字符串中的各個(gè)字符。如果字符是數(shù)字,則直接"將它傳送"給結(jié)果字符串
如果字符在A~Z之間,則查找對應(yīng)的手機(jī)鍵盤數(shù)字,并傳送該數(shù)字。
如果字符是其他內(nèi)容,則忽略它。
var LETTER_TO_NUMBER = {A:2,B:2,C:2,D:3,E:3,F:3,G:4,H:4,I:4,J:5,K:5,L:5,M:6,N:6,O:6,P:7,Q:7,R:7,S:7,T:8,U:8,V:8,W:9,X:9,Y:9,Z:9}; var phoneText = prompt("Enter a phone number (letters permitted)").toUpperCase(); var result = ""; for (var i=0;i練習(xí)在迭代另一類序列時(shí)也經(jīng)??吹絝or循環(huán):對象的鏈接結(jié)構(gòu)
var scores = { score:29, next:{ score:99, next:{ score:47, next:null } } }; var total = 0; for (var p=scores;p!=null;p=p.next) { total += p.score; }; alert(total);變量p引用了對象scores,并將p.score屬性運(yùn)算后賦值給變量total,并且每次執(zhí)行完代碼塊后,p引用的對象的屬性變?yōu)?b>p.next.score,下一次就是p.netx.next.score(scores.next.score→scores.next.next.score)下一個(gè)例子,演示嵌套循環(huán)。
var SIZE = 9 ; document.write("") for (var i=1;i<=SIZE;i++) { document.write("
")") for (var j=1;j<=SIZE;j++) { document.write(" "+i*j+" "); } document.write("") } document.write(" 編寫一個(gè)for語句,顯示10,然后顯示9,以此類推,知道最后顯示0。
for (var i=10;i>=0;i--) { console.log(i); }
var i = 10; while (i!==-1){ console.log(i); i--; }編寫一個(gè)小腳本,計(jì)算從1至20(含)的整數(shù)乘積值。使用for語句。
for (var i=1,n=1;i<21;i++) { n *= i; console.log(n); };4.4.3 for-in語句JavaScript包含一個(gè)迭代對象屬性名的語句。這門語言將這一操作稱為屬性名的枚舉。
var dog = { name:"Lisichka", breed:"G-SHEP", birthday:"2011-12-01" }; for (var p in dog) { alert(p) } // name breed birthday這個(gè)腳本將生成三條提示:一個(gè)給出name,一個(gè)給出breed,一個(gè)給出birthday。這些屬性的出現(xiàn)順序是任意的。試試另一個(gè)對象:
var colors = ["red","amber","green"]; for (var c in colors) { alert(c) } // 0 1 2枚舉是對屬性名進(jìn)行的,不是針對值。變量colors引用的對象的屬性名是0、1、2和length。但是,在運(yùn)行這一代碼時(shí),你只會(huì)看到顯示了0,1,2。為什么沒有l(wèi)ength?
其實(shí),一個(gè)對象的每個(gè)屬性,除了擁有值以外,還有幾個(gè)特性(attribute)。// 特性 在為真時(shí)的含義 writable 屬性的值可以修改 enumerable 這個(gè)屬性將出現(xiàn)在屬性的for-in枚舉中 configurable 可以從其對象中刪除這個(gè)屬性,它的特性值是可以改變的湊巧,數(shù)組的length屬性的enumerable特性被設(shè)置為false。由前面的例子知道,它的writable特性為true。
練習(xí)
修改與狗有關(guān)的小腳本,提示以下內(nèi)容:必須用for-in語句生成這些提示,并用object[property]符號提示屬性值。
var dog = {name:"Lisichka",breed:"G-SHEP",birthday:"2011-12-01"}; for (var i in dog) { document.write("The dog"s "+i+" is "+dog[i]+"4.5中斷
") } // dog[property]注意property是字符串類型,而不是變量。通常,語句都是按順序一次執(zhí)行一條。條件語句和迭代語句會(huì)稍微偏離這種有時(shí)被稱作直線式代碼的形式,但這種偏離是語句結(jié)構(gòu)本身決定的,很容易識別。但還四種語句的結(jié)構(gòu)化不是這么強(qiáng),他們對控制流的效果是中斷性的。有這些:
break,立即放棄執(zhí)行當(dāng)前正在執(zhí)行的switch或迭代語句;
continue,立即放棄一個(gè)迭代語句中當(dāng)前迭代的剩余部分;
return,立即放棄當(dāng)前執(zhí)行的函數(shù);
thorw,將在后面介紹;
4.5.1 break和continuebreak語句將立即終止整個(gè)循環(huán)。在搜索數(shù)組(或?qū)ο箧湥?,這一語句特別有用,它會(huì)在你找到正在查找的內(nèi)容之后立即終止搜索。
// 查找第一個(gè)偶數(shù)的索引位置 for (var i=0;icontinue語句立即開始循環(huán)的下一次迭代,而不在完成當(dāng)前迭代。當(dāng)循環(huán)中的一些(而非全部)迭代生成有用信息時(shí),這一語句非常有用。continue語句就是說“嗨,這次迭代里沒有什么要做的事情了,我馬上要開始下一次迭代了”。
// 計(jì)算一個(gè)數(shù)組中所有正數(shù)值之和 var array = [-1,3,12,3,-23,-23,-2,0,1,-12]; if (array[i]<=0) { continue; // 跳過非正數(shù) } sum += array[i]; } alert("Sumof positives is "+sum)這里接一個(gè)鏈接開源中國問題,是一個(gè)社友提的一個(gè)問題。剛好我在MDN里找到了一些文檔MDN-JS-break語句
那位社友的問題在于,在while循環(huán)中,當(dāng)i=4時(shí),就continue跳過了自增操作,按照MDN的說法,它將回到條件繼續(xù)執(zhí)行,這便成了一個(gè)死循環(huán)。而在for循環(huán)就直接each更新表達(dá)式了。
接下來寫一個(gè)腳本:用戶輸入一個(gè)數(shù)字,判斷是否為質(zhì)數(shù)。
var SmallLest = 2; var BigGest = 9E15; var n = prompt("輸入一個(gè)數(shù)字"); var condition = isNaN(n) || n % 1 !== 0 || n < SmallLest || n > BigGest; if (condition) { alert("只能判斷2~9e15之間的整數(shù)"); } else { var foundDivisor = "是"; // default,是質(zhì)數(shù) for (var k = 2,last = Math.sqrt(n);k <= last;k++) { if (n%k === 0) { // 2 ~ Math.sqrt(n)之間任何一個(gè)數(shù)可以整除n,則不是質(zhì)數(shù) foundDivisor = "不是"; break; } } } alert(n+" 是否為質(zhì)數(shù)? "+" : "+foundDivisor);最后一個(gè)關(guān)于break和continue的示例要研究一個(gè)問題:如何中斷外層循環(huán)?一種方法是對循環(huán)進(jìn)行標(biāo)記,然后在break語句中提及這個(gè)標(biāo)記。假定有一個(gè)對象紀(jì)錄了一組人選擇的彩票信息。
var picks = { Alice:[4,52,9,1,30,2], Boris:[14,9,3,6,22,40], Chi:[51,53,48,21,17,8], Dinh:[1,2,3,4,5,6], };另外,假定我們希望知道是否有人選擇了數(shù)字53。可以依次查看每個(gè)人選擇的數(shù)字,但只要找到53,就希望停止整個(gè)搜索,而不只是終止對當(dāng)前人員選擇數(shù)字的掃描。
var picks = { Alice:[4,52,9,1,30,2], Boris:[14,9,3,6,22,40], Chi:[51,53,48,21,17,8], Dinh:[1,2,3,4,5,6], }; var found = false; Search:for (var person in picks) { var choices = picks[person]; for (var i=0;i練習(xí)
重寫計(jì)算數(shù)組例子,改為使用break語句。
// continue重寫:計(jì)算一個(gè)數(shù)組所有正數(shù)值之和 var num = [1,3,4,-2,-12,-3,0,-3,-1]; var sum = 0; for (var i=0;i4.5.2 異常 有時(shí),運(yùn)行腳本會(huì)出現(xiàn)一些問題,可能是因?yàn)?strong>編碼錯(cuò)誤導(dǎo)致,如希望用乘法時(shí)卻編寫了加法。在這些情況下,腳本會(huì)一直運(yùn)行,但可能會(huì)給出錯(cuò)誤的結(jié)果。我們說這種腳本帶有bug。如果幸運(yùn)(居然叫幸運(yùn) - -)的話,還是能看到輸出結(jié)果,并會(huì)想到“這個(gè)結(jié)果不可能正確”,然后再去復(fù)查腳本,糾正錯(cuò)誤。 但有時(shí)運(yùn)行腳本,js遇到一個(gè)不能執(zhí)行的語句,或者不能求值的表達(dá)式。這是,腳本就不能繼續(xù)運(yùn)行了。引擎會(huì)拋出一個(gè)異常。如果沒有捕獲這個(gè)異常,腳本會(huì)立即停止運(yùn)行。我們稱之為崩潰 alert("Welcome to my script"); var message = printer+1; alert("The script is now ending")在腳本運(yùn)行時(shí),出現(xiàn)第一次提示,但由于第二條語句需要一個(gè)未聲明變量printer的值,所以引擎會(huì)拋出異常。因?yàn)檫@一異常未被捕獲,所以整個(gè)腳本都將被放棄,最后一條提示永遠(yuǎn)不會(huì)被執(zhí)行。
除了使用未聲明變量這種情況外,還有哪些錯(cuò)誤會(huì)被看作錯(cuò)誤,并導(dǎo)致JavaScript拋出異常呢?將數(shù)組長度設(shè)置為負(fù)值(RangeError)
從null值中讀取屬性(TypeError),因?yàn)橹挥袑ο髶碛袑傩?,JavaScript不能將null轉(zhuǎn)換為對象
執(zhí)行不合乎JavaScript語法的代碼,或?qū)ζ淝笾担?b>SyntaxError)
var a = [10,20,30]; a.length = -5; // "Uncaught RangeError: Invalid array length" var a = null; alert(a[3]); // "Uncaught TypeError: Cannot read property "3" of null" alert(3/-) // "Uncaught SyntaxError: Unexpected token )"我們可以使用JavaScript的throw語句在自己的代碼中顯式的拋出異常??梢話伋鲎约合胍娜魏沃?;在下面的例子中,將拋出一個(gè)字符串:
alert("Welcome to my script") throw "Ha ha ha"; // "Uncaught Ha ha ha" alert("You will never see this message")我們提到,未捕獲的異常會(huì)導(dǎo)致腳本崩潰。要捕獲異常,可以使用try-catch語句。
try { // 這是一個(gè)人為設(shè)計(jì)的示例,只說明了一個(gè)點(diǎn) alert("Welcome to my script"); throw "Ha ha ha"; alert("You will never see this script"); } catch(e) { alert("Caught : "+e); }catch子句將一個(gè)變量(在本例中是e,這是一個(gè)相當(dāng)常見的選擇)初始化(或理解為將拋出的值賦值給e?)為被拋出的值。在實(shí)踐中,許多JavaScript程序員都需要拋出帶有各種屬性的對象,用以提供一些信息,用以提供一些信息,來為其描述拋出此異常的問題。例如:
throw {reason:"class full",limit:20,date:"2012-12-22"} // "Uncaught #異常為特定的編程問題提供了非常自然的解決方案。只要你意識到,利用你當(dāng)前擁有的數(shù)據(jù),一個(gè)計(jì)算不能正常進(jìn)行,那就應(yīng)該拋出異常。
和大多數(shù)程序設(shè)計(jì)特性一樣,異常也可能被濫用。下面這個(gè)腳本要求用戶從三扇分別標(biāo)有1,2,3的門中選擇一扇,并贏得藏在這扇門之后的獎(jiǎng)勵(lì)。// 如果沒有異常這將是更好的一個(gè)腳本 try{ var PRIZES = ["a new car","a broken stapler","a refrigerator"]; var door = prompt("Enter a door number(1,2,or3)"); var prize = PRIZES[door-1]; alert("You have won "+prize.toUpperCase()+"!!"); }catch(e){ alert("Sorry, no such door.") }如果用戶輸入除1,2,3之外的任何值,prize的值都將是undefined,對undefined調(diào)用toUpperCase將會(huì)拋出一個(gè)異常。這個(gè)異常被捕獲,并報(bào)告一條錯(cuò)誤。這一點(diǎn)很難通過研究代碼來發(fā)現(xiàn),因此,我們說這一腳本的邏輯有些費(fèi)解。他依賴于我們調(diào)用toUpperCase這一事實(shí),它與輸入無效門牌號的"問題"沒有什么關(guān)系!我們最后用一個(gè)簡單的if語句立即核實(shí)輸入。
練習(xí)在JavaScript中除以零是否會(huì)拋出異常?
正數(shù)除0結(jié)果為Infinity,負(fù)數(shù)除0為-Infinity,0除以0為NaN。
重寫關(guān)于三個(gè)獎(jiǎng)勵(lì)的例子,不使用異常
var PRIZES = ["a new car","a broken stapler","a refrigerator"]; var door = prompt("Enter a door number(1,2,or3)"); if (door==1 || door==2 || door==3) { alert("You have won "+PRIZES[door-1]+"!!"); } else { alert("Please Input number 1,2or3") }4.6 應(yīng)該避免的編碼風(fēng)格我們已經(jīng)給出了以下一般形式的if、while、do-while、for和for-in語句
if (test) { stmts } if (test) { stmts } else { stmts } if (test) { stmts } else if (test) { stmts } if (test) { stmts } else if (test) { stmts } else { stmts } while (test) { stmts } do { stmts } while (test); for (init;test;each) { stmts } for (var variable in object) { stmts }但事實(shí)上,上面使用語句序列(放在大括號)的位置,JavaScript都允許使用單個(gè)語句,下面這種寫法完全合法;
if (count === 0) break; // 或者 if (count === 0) break; // 但不一定是最好的 if (count === 0) { break; }從技術(shù)角度來說,任何一個(gè)放在大括號中的語句序列,其本身就是單條語句,成為塊語句。因此,在任何需要使用單條語句的地方都可以使用塊語句,但在實(shí)踐中,如果只是為了使用塊語句而使用塊語句,看起來會(huì)很傻。下面的腳本雖然有點(diǎn)傻,確實(shí)合法的;
{{{{alert("Hello");}}}}強(qiáng)烈建議遵循現(xiàn)在編碼約定,僅在if語句和迭代語句中使用塊語句。我們還強(qiáng)烈建議,應(yīng)當(dāng)始終使用塊語句來構(gòu)建這兩種語句,哪怕簡短形式可以減少鍵入工作。主要理由如下:如果代碼中有些語句使用大括號,有些不使用,視覺上還會(huì)顯得有些不協(xié)調(diào)。當(dāng)在同一條if語句中,有些候選項(xiàng)帶有大括號,而另一些沒有時(shí),看起來尤其糟糕。缺乏一致性會(huì)讓代碼顯得不平衡、不整潔、需要花費(fèi)大量不必要的精力來領(lǐng)會(huì)其意圖。
如果缺少大括號,在修改代碼時(shí)更容易引入錯(cuò)誤。這里有一個(gè)示范。
// 下面的腳本顯示數(shù)字0至9的平方 for (var i=0;i<=10;i++) { alert(i+" squared is "+(i*i)) };程序員決定向循環(huán)體中添加一條語句,定義一個(gè)新變量,用來保存計(jì)算所得的平方,但卻忘了添加大括號
for (var i=0;i<10;i++) var square = i * i; alert(i+" squared is "+square);因?yàn)閒or循環(huán)體總是跟在控制表達(dá)式(放在小括號)之后的單條語句,所以這個(gè)腳本聲明了變量square,并重復(fù)為它賦值,最后一次為81.在for語句完成之后將出現(xiàn)提示。這時(shí),i的值為10,所以整個(gè)腳本給出單條提示:10 squared is 81,如果養(yǎng)成了符合語句中使用大括號的習(xí)慣,就永遠(yuǎn)不會(huì)犯這樣的錯(cuò)誤。
僅在if語句和迭代語句中使用塊語句,而且在這兩種語句中也總要使用塊語句
4.6.2 隱式分號官方的JavaScript定義聲明,以下語句應(yīng)當(dāng)以分號(;)結(jié)束:變量聲明語句、表達(dá)式語句(包括賦值)、do-while語句、continue語句、break、return語句和throw語句。
4.6.3 隱式聲明
但是這門語言的設(shè)計(jì)者允許程序員根據(jù)自己的一元省略語句末尾的分號,依靠JavaScript引擎來指出哪個(gè)地方應(yīng)當(dāng)有分號。遺憾的是,這一規(guī)則降低了我們將長語句分跨在多行代碼的靈活性。關(guān)于處理缺失分號的技巧細(xì)節(jié),可在官文中找到。當(dāng)你嘗試使用一個(gè)尚未聲明的變量時(shí),JavaScript引擎會(huì)拋出一個(gè)異常。但是,如果嘗試為一個(gè)未聲明的變量賦值,JavaScript會(huì)自動(dòng)為你聲明這個(gè)變量。
// 假定變量next_song從來沒有聲明過 next_song = "Purple Haze";這個(gè)腳本不會(huì)拋出異常!許多人可能會(huì)說它應(yīng)該拋出異常的,許多專家認(rèn)為這個(gè)隱式聲明是語言設(shè)計(jì)缺陷。在賦值中意外地錯(cuò)誤拼寫一個(gè)變量名,會(huì)導(dǎo)致一個(gè)新變量的聲明,它不同與你本來想要賦值的變量。這個(gè)腳本將一直運(yùn)行,只到發(fā)生了某些“跑偏道路”的事情,是錯(cuò)誤很難查找。如果引擎在賦值時(shí)拋出異常,哪會(huì)更好一些,因?yàn)檫@個(gè)錯(cuò)誤的偵測就很容易了。
4.6.4 遞增和遞減運(yùn)算符 這里可能用到優(yōu)先級表文檔:MDNJavaScript運(yùn)算符優(yōu)先級
千萬不要依賴這一“功能“,JSLint很明智的將它的應(yīng)用報(bào)告為錯(cuò)誤。var x = 5; x++; // x:6 var y = x++; // y:6 x:7 等號右結(jié)合 var z = ++x; // x:8 z:8 var w = ++y + z++; // y:7,w:15,z:9等號結(jié)合性為右結(jié)合,故對=右側(cè)開始計(jì)算,最后賦值給變量x。x:5
后置遞增,先計(jì)算x(使用x),最后再進(jìn)行自增。x:6
出現(xiàn)的符號:=、后置++,后置自增無結(jié)合性,則先賦值(使用x)y:6,后自增x:7
出現(xiàn)的符號:=、++前置,兩者結(jié)合性都是右結(jié)合,則先自增x:8,后賦值z:8
出現(xiàn)的符號:=、前置++、+、后置++,加括號應(yīng)該是:(var w = ((++y) + z))++,先對前置自增運(yùn)算y:7,然先使用z與y相加w:15,賦值給變量w,最后z才自增。所以y:7,w:15,z:9
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/91673.html
摘要:語句包含聲明語句表達(dá)式語句條件語句循環(huán)語句和中斷語句我們可以將表達(dá)式的求值結(jié)果存儲在變量中,在將來提取它們。變量在使用之前應(yīng)當(dāng)聲明。程序員可以用語句顯式拋出異常。程序員需要保護(hù)自己總是明確使用分號來終結(jié)聲明語句。 主要總結(jié): 一個(gè)腳本就是一個(gè)語句序列,其中每條語句都會(huì)生成某一操作。JavaScript語句包含:聲明語句、表達(dá)式語句、條件語句、循環(huán)語句和中斷語句 我們可以將表達(dá)式的求...
摘要:這時(shí)候控制臺看到的是對象的快照,然而點(diǎn)開看詳情的話是這段代碼在運(yùn)行的時(shí)候,瀏覽器可能會(huì)認(rèn)為需要把控制臺延遲到后臺,這種情況下,等到瀏覽器控制臺輸出對象內(nèi)容時(shí),可能已經(jīng)運(yùn)行,因此會(huì)在點(diǎn)開的時(shí)候顯示,這是的異步化造成的。 本書屬于基礎(chǔ)類書籍,會(huì)有比較多的基礎(chǔ)知識,所以這里僅記錄平常不怎么容易注意到的知識點(diǎn),不會(huì)全記,供大家和自己翻閱; 上中下三本的讀書筆記: 《你不知道的JavaScri...
摘要:先推薦一個(gè)我自己寫的模板引擎,項(xiàng)目地址。下面就是總結(jié)的編寫模板引擎的幾個(gè)步驟例如一個(gè)模板為最終會(huì)編譯成為一個(gè)函數(shù)可以觀察到模板中的所有的變量名都被指定成了參數(shù)對象的屬性,并且該函數(shù)自始至終只做了一件事,就是構(gòu)建字符串,并將其返回。 showImg(https://segmentfault.com/img/remote/1460000007498588?w=300&h=113); 先推薦...
摘要:對象被傳遞到從句中被捕獲。一些語言提供了尾遞歸優(yōu)化。這意味著如果一個(gè)函數(shù)返回自身遞歸調(diào)用的結(jié)果,那么調(diào)用的過程會(huì)被替換為一個(gè)循環(huán),可以顯著提高速度。構(gòu)建一個(gè)帶尾遞歸的函數(shù)。語言精粹讀書筆記函數(shù) 第四章 函數(shù) Functions (二) 參數(shù) arguments arguments數(shù)組: 函數(shù)可以通過此參數(shù)訪問所有它被調(diào)用時(shí)傳遞給它的參數(shù)列表,包括哪些沒有被分配給函數(shù)聲明時(shí)定義的形式參數(shù)...
摘要:在中雖然對象通過標(biāo)記清除的方式進(jìn)行垃圾收,但與對象卻是通過引用計(jì)數(shù)回收垃圾的,也就是說只要涉及及就會(huì)出現(xiàn)循環(huán)引用問題。如果垃圾收集例程回收的內(nèi)存分配量低于,則變量字面量和或數(shù)組元素的臨界值就會(huì)加倍。 只挑本人重要的寫(有夾雜其他補(bǔ)充) 基本類型和引用類型的值 描述:基本類型值指的是簡單的數(shù)據(jù)段,而引用類型值指那些可能由多個(gè)值構(gòu)成的對象。 動(dòng)態(tài)的屬性 引用類型的值,我們可以為其添加屬性和...
閱讀 2508·2021-11-24 09:39
閱讀 3553·2019-08-30 15:53
閱讀 631·2019-08-29 15:15
閱讀 2936·2019-08-26 13:23
閱讀 3259·2019-08-26 10:48
閱讀 679·2019-08-26 10:31
閱讀 808·2019-08-26 10:30
閱讀 2393·2019-08-23 18:32