JavaScript 語法

語法(grammar)

本篇文章中主要探討 JavaScript 中一些容易讓人產(chǎn)生困惑、誤解的語法。

1. 語句(statement)和表達式(expression)

在計算機語言中,執(zhí)行特定任務(wù)的一組單詞、數(shù)字和運算符被稱為語句。如下:

a = b * 2;

語句由一個或多個表達式組成。表達式是對一個變量或值的引用,或者是一組值和變量與運算符的組合,可以返回一個結(jié)果值。

舉例來說,a = b * 2; 這個語句中有四個表達式。

  • 2 是一個字面值表達式。
  • b 是一個變量表達式,表示獲取它的當(dāng)前值。
  • b * 2 是一個算術(shù)表達式,表示進行乘法運算。
  • a = b * 2 是一個賦值表達式,意思是將表達式 b * 2 的結(jié)果賦值給變量 a。

1.1 語句的結(jié)果值

語句也會有一個結(jié)果值,獲取語句結(jié)果值的最直接辦法就是在控制臺輸入語句,默認(rèn)情況下控制臺會打印出最后一條語句的結(jié)果值。

// 該表達式的結(jié)果值是 undefined,因為 var 的結(jié)果值是 undefined
var a = 3 * 6;

在代碼中,是無法獲取結(jié)果值的,語法暫時不允許將獲得語句的結(jié)果值賦值給變量:

// 該語句的結(jié)果值是 42,即最后一個語句 b = 4 + 38 的結(jié)果值
var b;
if (true) {
  b = 4 + 38;
}

不過可以通過 eval 得到結(jié)果值(開發(fā)中避免使用):

var a, b;
a = eval("if (true) { b = 4 + 38; }");
a; // 42

1.2 表達式的副作用

大部分表達式?jīng)]有副作用,副作用會將變量的值改變。比如遞增運算符++,執(zhí)行完成后會,變量本身會被改變。

如下表達式會報錯,根據(jù)優(yōu)先級首先執(zhí)行 a++,返回 42,然后執(zhí)行 ++42,這時候就會報錯,因為 ++ 無法直接 在 42 這樣的值上產(chǎn)生副作用。

++a++; // ReferenceError

2. 自動分號

有時 JavaScript 會自動為代碼行補上缺失的分號,即自動分號插入(Automatic Semicolon Insertion,ASI)。

注意: ASI 只在換行符處起作用,而不會在代碼行的中間插入分號。

如果 JavaScript 解析器發(fā)現(xiàn)代碼行可能因為缺失分號而導(dǎo)致錯誤,那么它就會自動補上分號。并且,只有在代碼行末尾與換行符之間
除了空格和注釋之外沒有別的內(nèi)容時,它才會這樣做。

如下代碼,會在 b 之后補上分號:

var a = 42, b
c;

另外及 ASI 的情況是 break、continue、return 和 yield(ES6)等關(guān)鍵字。

ASI 是一個語法糾錯機制。不要為了追求“代碼的美觀”,省去一些鍵盤輸入。所以在所有需要的地方加上分號,將對 ASI 的依賴降到最低。

3. try...finally

finally 中的代碼總是會在 try 之后執(zhí)行,如果有 catch 的話則在 catch 之后執(zhí)行。

3.1 try 中有 return 語句

如下 return 先執(zhí)行,將 foo 的返回值設(shè)置為 42,當(dāng) try 執(zhí)行完畢,接著執(zhí)行 finally,最后函數(shù)執(zhí)行完畢。

function foo() {
  try {
    return 42;
  } finally {
    console.log("Hello");
  }
  console.log("never runs");
}
console.log(foo());

// Hello
// 42

3.2 try 中的 throw

規(guī)則同上。

function foo() {
  try {
    throw 42;
  } finally {
    console.log("Hello");
  }
  console.log("never runs");
}

console.log(foo());
// Hello
// Uncaught Exception: 42

3.3 finally 中拋出異常

如果 finally 中拋出異常,函數(shù)就會終止,try 中 return 設(shè)置的返回值也會被丟棄:

function foo() {
  try {
    return 42;
  } finally {
    throw "Oops!";
    console.log("never runs");
  }
}
console.log(foo()); // Uncaught Exception: Oops!

3.4 try 中的 continue 和 break

如下,continue 在每次循環(huán)之后,會在 i++ 執(zhí)行之前執(zhí)行 console.log(i)

for (var i = 0; i < 10; i++) {
  try {
    continue;
  } finally {
    console.log(i);
  }
}
// 0 1 2 3 4 5 6 7 8 9

3.5 finally 中的 return

finally 中的 return 會覆蓋 try 和 catch 中 return 的返回值:

function foo() {
  try {
    return 42;
  } finally {
    // 沒有返回語句,所以沒有覆蓋
  }
}
function bar() {
  try {
    return 42;
  } finally {
    // 覆蓋前面的 return 42
    return;
  }
}
function baz() {
  try {
    return 42;
  } finally {
    // 覆蓋前面的 return 42
    return "Hello";
  }
}
foo(); // 42
bar(); // undefined
baz(); // Hello

4. switch

case 表達式的匹配算法與 === 相同。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容