表達式在JS中是短語,語句是JS整句或命令。
JS程序就是一系列可執行語句的集合。
表達式計算一個值,語句用來執行以使某件事情發生。
“使某件事情發生”的一個方法是計算帶有副作用的表達式。
另一種“使某件事情發生”的方法是改變語句的默認執行順序。
(條件語句,循環語句,跳轉語句。)
表達式語句
一些有副作用的表達式,是可以作爲單獨的語句的,這種把表達式當作語句的用法也稱作表達式語句。
具有副作用的表達式是JS中最簡單的語句。
- 賦值語句
greeting = “Hello” + name;
i *= 3;
- 遞增運算符++,遞減運算符- -
counter ++;
- delete運算符
delete o.x;
- 函數調用
alert(greeting);
window.close();
複合語句和空語句
JavaScript中還可以將多條語句聯合在一起,形成一條複合語句。
- 使用花括號括起來
- 語句塊結尾不需要分號,塊中的原始語句必須以分號結束。
- 建議縮進,增強代碼可讀性。
- JavaSrcipt中沒有塊級作用域,在語句塊中聲明的變量並不是語句私有的。
當創建一個具有空循環體的循環時,可以使用空語句。
for (i = 0; i < a.length; a[i++] = 0);
在這個循環中,所有的操作都在表達式a[i++]=0中完成,這裏並不需要任何循環體。然而JS需要循環體中至少包含一條語句,因此,這裏只使用了一個分號來表示一條空語句。
注意,在 for,while 循環或 if 語句的右圓括號後的分好很不起眼,這很可能造成一些致命bug,而這些bug很難定位到。例如,下面的代碼執行結果可能就不是程序作者想要的效果:
if((a == 0) || (b == 0)); // 這一行代碼什麼也沒做。
o = null; // 這一行代碼總是會執行。
如果有特殊的目的需要使用空語句,最好在代碼中添加註釋,這樣可以更加清楚地說明這條空語句是有用的:
for(i = 0; i < a.length; a[i++] = 0) /* empty */;
聲明語句
var 和 function 都是聲明語句,它們聲明或定義變量或函數。這些語句定義標識符並給其賦值。
- var
var i ;
var j = 0;
var p,q;
var greeting = 'hello' + name;
var x = 2.34, y = Math.cos(0.75);
- 如果var語句出現在函數體內,那麼它定義的是一個局部變量,其作用域就是這個函數。如果在頂層代碼中使用var語句,它聲明的是全局變量,在整個JS程序中都是可見的。
- var聲明的變量是無法通過delete刪除的。
- 如果var語句中的變量沒有指定初始化表達式,那麼這個變量的值初始爲undefined。
- 變量在聲明它們的腳本或函數中都是有定義的,變量聲明語句會被‘提前’至腳本或函數的頂部。但是初始化的操作則還在原來var語句的位置執行,在聲明語句之前變量的值是undefined。
- var語句同樣可以作爲for循環或者for/in循環的組成部分(和在循環之外的變量聲明一樣,這裏聲明的變量也會‘提前’)。
- function
關鍵字function用來定義函數,寫成語句形式
function f(x) {return x + 1} // 含有變量名的語句
函數定義表達式
var f = function(x) {return x + 1} //將表達式賦值給一個變量
在定義函數時,並不執行函數體內的語句,它和調用函數時待執行的新函數對象相關聯。
條件語句
- if,else if 語句
if語句在程序執行過程中創建一條分支,並且可以使用else if來處理多條分支。
if (username == null) // 如果username是null或undefined
username = 'John Doe'; // 對其進行定義
if (!username) username = 'John Doe';
// 當username的值爲假值時,!username的值爲真值,
// 執行條件語句內容。
// 如果username是null,undefined,false,0,'' 或者NaN,
// 那麼給它賦一個新值。
switch 語句
所有分支語句依賴於同一個表達式的值時使用。
switch(n){
case 1: // 如果 n === 1 ,從這裏開始執行
// 執行代碼塊1
break; // 停止執行switch語句
case 2:
// 執行代碼塊2
break;
case 3:
// 執行代碼塊3
break;
default:
// 執行代碼塊4
break;
}
function convert(x){
switch(typeof x){
case 'number': //將數字轉換爲十六進制數
return x.toString(16);
case 'string': //返回兩端帶雙引號的字符串
return '"' + x + '"';
default: //使用普通的方法轉換其他類型
return String(x);
}
}
由於每次執行switch語句的時候,並不是所有的case表達式都能執行到,因此,應當避免使用帶有副作用的case表達式,比如函數調用表達式和賦值表達式。最安全的做法就是在case表達式中使用常量表達式。
‘default’ 默認標籤,當case都不滿足時,執行default語句塊。最合理的方式放在末尾,但實際上可以放置在switch語句內的任何地方。
循環語句
- while語句
var count = 0;
while (count < 10){
console.log(count);
count++;
}
- do/while語句
在循環尾部檢測循環表達式,這意味着循環體至少會執行一次。
do{
statement
}while(expression);
- for語句
for(initialize初始化;test檢測;increment更新){
//第一步先初始化
//然後進行判定
//執行循環語句內容!!!
//更新循環控制
statement
}
var i,j;
for(i = 0, j = 10; i < 10; i++,j--)
sum += i * j;
循環變量不一定都是數字。
function tail(o){
for(; o.next; o = o.next)/* empty */;
// 判斷o.next是不是真值來執行遍歷
return o;
}
- for/in語句
for (variable in object)
statement
變量,object表達式計算結果是對象。
在執行過程中,JS解釋器首先計算object表達式。如果表達式爲null或者undefined,JS解釋器將會跳過循環並執行後續的代碼。如果表達式是一個原始值將會轉換爲與之對應的包裝對象。否則其本身就是對象。JS會依次枚舉對象的屬性來執行循環。然而在每次循環之前,JS都會先計算variable表達式的值,並將屬性名賦值 給它。
跳轉語句
- 標籤語句
語句是可以添加標籤的,標籤是由語句前的標識符和冒號組成:
indentifier:statement
通過給語句定義標籤,就可以在程序的任何地方通過標籤名引用這條語句。
break和continue是JS中唯一可以使用語句標籤的語句。
標籤的命名空間和變量或函數的命名空間是不同的,因此可以使用同一個標識符作爲語句標籤和作爲變量名或函數名。
語句標籤只有在它所起作用的語句內是有定義的。
- break 語句
單獨使用break語句的作用是立即退出最內層的循環或switch語句。
for(var i = 0; i < a.length; i++){
if(a[i] == target) break;
}
JS允許break關鍵字後面跟隨一個語句標籤:
break labername;// 在關鍵字break和labelname之間不能換行。
// 因爲JS解釋器會給語句自動補全省略掉的分號。
當break和標籤一塊使用時,程序將跳轉到這個標籤所標識的語句塊的結束,或者直接終止這個閉合語句塊的執行。
當你希望通過break來跳出非就近的循環體或者switch語句時,就會用到帶標籤的break語句。即跳出多層次嵌套的循環體邏輯。
// 從標籤名開始,以便在報錯時推出程序
compute_sum:if(Matrix){
for(var x = 0; x < martix.length; x++){
var row = martix[x];
if(!row) break compute_sum;
for (var y = 0; y < row.length; y++){
var cell = row[y];
if (isnan(cell)) break compute_sum;
sum += cell;
}
}
success = true;
}
// break語句跳轉至此
不管break語句帶不帶標籤,它的控制權都無法越過函數的邊界。比如,對於一條帶標籤的函數定義語句來說,不能從函數內部通過這個標籤來跳轉到函數外部。
if語句不能單獨使用break語句,只能在嵌套時使用。
- continue 語句
這個語句是轉而執行下一次循環。
這個語句同樣可以帶有標籤:
continue labelname
當執行到continue語句的時候,當前的循環邏輯就終止了,隨即執行下一次循環,在不同類型的循環中,continue的行爲也有所區別:
- 在while循環中,在循環開始處的條件判定會重複檢測,如果檢測結果爲true,循環體會從頭開始執行。
- 在do\while循環中,程序的執行直接跳到循環結尾處,這時會重新判斷循環條件,之後會繼續下一次循環。
- 在for循環中,首先計算自增表達式,然後再次檢測test表達式,用以判斷是否執行循環體。
- 在for\in循環中,循環開始遍歷下一個屬性名,這個屬性名賦給了指定的變量。
注意continue語句在while和for循環中的區別,while循環直接進入下一輪的循環條件判斷,但for循環首先計算其自增表達式,然後判斷循環條件。
- return 語句
函數調用是一種表達式,而所有表達式都有值。函數中的return語句既是指定函數調用後的返回值。
return expression;
return語句只能在函數體內出現,如果不是的話會報錯。
當執行到return語句的時候,函數終止執行,並返回expression的值給調用程序。
function square(x){ return x*x; }
square(2) // 調用結果爲4
如果沒有return語句,則函數調用僅依次執行函數體內的每一條語句直到函數結束,最後返回調用程序。這種情況下,調用表達式大的結果是undefined。
throw 語句
所謂異常(exception)是當發生了某種異常情況或錯誤時產生的一個信號。
拋出異常,就是用信號通知發生了錯誤或異常狀況。
捕獲異常是指處理這個信號,即採取必要的手段從異常中恢復。
throw語句會顯式的拋出異常。
throw expression
語句可以拋出一個代表錯誤代碼的數字,或者包含可讀的錯誤消息的字符串。當Js解釋器拋出異常的時候通常採用error類型和其子類型。
new Error(‘message’)
function factorial(x){
// 如果輸入參數是非法的,則拋出一個異常
if (x > 0)throw new Error(‘x不能是負數’);
// 否則,計算出一個值,並正常地返回它
for(var f = 1; x > 1; f *= x, x- -)/*empty*/;
return f;
}
當拋出異常時,js解釋器會立即停止當前正在執行的邏輯,並跳轉至就近的異常處理程序。
- try/catch/finally 語句
這條語句是js的異常處理機制。
try語句定義了需要處理的異常所在的代碼塊。
catch從句跟隨在try語句之後,當try語句塊內發生異常,調用catch內的代碼邏輯。
finally塊內放置清理代碼,不管try塊中是否產生異常,finally塊內的邏輯總是會執行。
try {
// 通常來講,這裏的代碼會從頭執行到尾而不會產生任何問題,
// 但有時會拋出一個異常,要麼是由throw語句直接拋出異常
// 要麼是通過調用一個方法間接的拋出異常
}
catch(e){
// 當且僅當try語句塊拋出了異常,纔會執行這裏的代碼
// 這裏可以通過局部變量e來獲得對Error對象或者拋出的其他值的引用,
// 這裏的代碼塊可以基於某種原因處理這個異常,也可以忽略這個異常,
// 還可以通過throw語句重新拋出異常
}
finally{
// 不管try語句塊是否拋出了異常,這裏的邏輯總是會執行,終止try語句塊的方式有:
// 1)正常終止
// 2)通過break,continue或return語句
// 3)拋出一個異常,異常被catch從句捕獲
// 4)拋出一個異常,異常未被捕獲,繼續向上傳播
}
其它語句類型
- with 語句
with語句用於臨時擴展作用域鏈。
with(object)
statement
這條語句將object添加到作用域鏈的頭部,然後執行statement,最後把作用域鏈恢復到原始狀態。
with語句的缺點:優化難,運行慢。
- debugger 語句
該語句可以產生一個斷點。JS的執行會停止在斷點的位置,這時候可以使用調試器輸出變量的值,檢查調用棧等。
- ‘use strict’
‘ use strict ’ 是ES5引入的一條指令。指令不是語句,很接近。
‘ use strict ’ 指令和普通語句之間的區別:
- 它不包含任何語言的關鍵字,指令僅僅是一個包含一個特殊字符串直接量的表達式,對於那些沒有實現ES5的JS解釋器來說,它只是一條沒有副作用的表達式語句。將來的ES標準希望將use用來做關鍵字。
- 它只能出現在腳本代碼的開始或者函數體的開始,任何實體語句之前。但不一定出現在腳本的首行或函數體的首行。因爲 ‘ use strict ’ 指令之後或之前都可能有其他字符串直接量表達式語句,並且JS的具體實現可能將它們解析爲解釋器自有的指令。在腳本或者函數體內第一條常規語句之後字符串直接量表達式語句只當做普通的表達式語句對待;它們不會當做指令解析,它們也沒有任何副作用。
使用指令後的代碼是嚴格代碼。嚴格代碼以嚴格模式執行。
嚴格模式的內容:
- 禁止with語句
- 所有變量先聲明後賦值
- 調用的函數(不是方法)中的一個this值是undefined。(在非嚴格模式下,調用的函數中的this值總是全局對象)。可以利用這種特性來判斷JS是否支持嚴格模式:
var hasStrictMode = (function (){"use strict";return this===undefined}());