語句和表達式
語句和表達式的區別就像英語中的句子和短語的區別一樣,多個表達式通過標點符號或者連接詞連接成語句
JavaScript中表達式可以返回一個結果值
var a = 3 * 6;
var b = a;
b;
這三行代碼都是包含表達式的語句
其中 第一行的3*6 , 第二行的a , 第三行的b都是一個表達式,結果值都是18
var a=3*6和var b=a被稱爲"聲明語句",因爲他們聲明瞭變量
a=3*6和b=a(不帶var)叫"賦值表達式".
第三行代碼只有一個表達式b,同時也是一個語句,被稱爲"表達式語句"
語句的結果值
每個語句都有一個結果值(undefined也算)
獲得結果值最直接的方法是在瀏覽器控制檯中輸入語句,默認情況下控制檯會顯示所執行的最後一條語句的值
如 輸入 b=a ,其結果值是賦給b的值
但 規範定義var 的結果值是undefined,如果在控制檯中輸入var a= 42會得到undefined而不是42
(ES5中其實變量聲明算法是有一個返回值的(是一個包含聲明變量名稱的字符串),但是這個值被變量語句算法屏蔽掉了(for..in除外))
但是在代碼中我們無法直接獲取這個結果值(賦值表達式,表達式語句除外)
先來看看其他語句
比如代碼塊{..}的結果值是最後一個語句/表達式的結果
換句話來說,代碼塊的結果值就如同一個隱式的返回,即返回最後一個語句的結果值
但下面這樣的代碼無法運行
a = if(true) {
b = 2;
}//Uncaught SyntaxError
因爲語法不允許我們獲得語句的結果值並賦給另一個變量
那應該怎麼獲取語句的結果值呢
a = eval(`if(true) {
b = 2;
}`);
a; //2
注意!! 永遠不要在實際開發中使用這種方法!!會導致代碼運行速度變慢!!(具體原因看這篇)
ES7中有一項提案 "do表達式" (未實裝)
a = do {
if(true) {
b = 2;
}
}
類似於這樣,do{..}表達式執行一個代碼塊,並返回最後一個語句的結果值,然後賦值給a
表達式的行爲
表達式除了會返回一個結果值,還會有一些附加的行爲
比如
var a = 42;
var b = a++;
其中a=42和b=a++(不帶var)都是一個賦值表達式
a++首先返回變量a的當前值42(再將該值賦給b),然後將a的值加1(附加行爲)
遞增運算符++和遞減運算符--都是一元運算符(會強制轉換爲數字),她們既可以用在操作數的前面,也可以用在後面
在前面的時候,如++a,她的附加行爲(將a遞增)產生在表達式返回結果之前,在後面的時候,則發生在表達式返回結果之後
而++a++則會報錯,根據優先級會先執行a++,返回結果值42,然後執行++42,這時候會產生ReferenceError錯誤
還有一種常見的誤解是()能將a++的行爲封裝起來
然而事實上(a++)還是會先返回原本的值後在執行加1的行爲,除非在++後再次對a進行運算
比如(a++,a)
(由於優先級的關係,所以需要放在括號中)
返回的是最後一個語句的結果值,也就是a+1後的值
var a = 42;
var b = (a++, a);
b; //43
標籤語句
類似於 foo:fun() 這樣的語法叫做標籤語句,foo是語句fun()的標籤
使用情形如下,continue foo的作用是執行foo循環的下一輪循環,直接寫continue的話,則是執行當前循環的下一循環
foo: for(let i = 1; i < 3; i++) {
for(let j = 1; j < 3; j++) {
console.log(i, j);
if(i == j) {
continue foo;
}
}
}
注意, continue ___只能對帶標籤的循環代碼使用
但是 break ___可以對帶標籤非循環代碼使用,作用是挑出標籤___所在的循環/代碼塊
(function() {
foo: {
console.log("hello");
break foo;
console.log("never show");
}
})()