介紹
第五章主要講解 JavaScript 中的語句,其中主要內容涉及到 迴圈語句、跳轉標籤、跳轉語句、try/catch、嚴格模式 等
自我提問
-
什麼是跳轉標籤,使用場景是什麼?
-
下面的程式碼執行後會怎樣列印?
(function() { try { console.log('return'); return; } catch (error) { } finally { console.log('finally'); } })(); console.log('end'); 複製程式碼
const a = 1; switch (a) { case '1': console.log(1); case 1: console.log(2); case 2: console.log(3); case 3: console.log(4); break; default: console.log(5); } 複製程式碼
-
執行下面的 for/in 語句會發生什麼?
const o = { x: 1, y: 2, z: 3 }, a = []; let i = 0; for (a[i++] in o); 複製程式碼
for(let a in null) { console.log(1); } 複製程式碼
-
嚴格模式有什麼特點?
腦圖
關鍵知識點
語句的定義
語句是整句或命令。表示式用來計算一個值,語句用來執行來使某件事發生。
語句型別
表示式語句
具有副作用的表示式是最簡單的語句
空語句
一個 ; 便為一個空語句(按照定義,語句讓某件事情發生,但是空語句什麼都不會發生,這些概念的東西真是看不懂)
複合語句
將多個語句聯合在一起便可形成一條複合語句
宣告語句
var、function 均為宣告語句,但是函式宣告語句不能出現在 if、while 等語句中,所以標準並沒有把函式宣告歸類為真正的語句(感覺有點奇怪,變數宣告和函式宣告都不能出現在 if 的條件判斷中)
條件語句
條件語句包括 if, while,else if 不是單個語句,而是 else 和 if 合併的複合語句
迴圈語句
常見的迴圈語句語句 for、while、do/while、for/in
跳轉語句
常見的跳轉語句有 return、break、continue、throw
其它語句
其它的還有如 with、debugger,('use strict;' 不是語句,而是一個字串直接量指令)
空語句的用法
空語句最常見的用法,是用來初始化一個陣列。
for (i = 0; i < a.length; a[i++] = 0) ;
複製程式碼
switch 語句的注意點
- switch 中 使用 === 來進行匹配
- return、break 都可以用來終止 switch
- switch 匹配後 如果不使用 return、break 中斷,將會一直向下執行所有的 case 中的語句直到最後,俗稱
case 穿透
,初用最常見的坑點
const a = 1;
switch (a) {
case '1':
console.log(1);
case 1:
console.log(2);
case 2:
console.log(3);
case 3:
console.log(4);
break;
default:
console.log(5);
}
// 2 3 4
複製程式碼
for in 語句注意點
- for(varible in obj) 中 obj 的值為 null、undefined 時,將會跳過(不會報錯),其它原始值會轉換為對應的包裝物件
- for/in 只會遍歷可列舉屬性,遍歷過程中刪除的未列舉的屬性,正常將不會被列舉到,新增的屬性正常也不會列舉到
- 一般瀏覽器會按照屬性定義的前後列舉屬性,但是 不應該依賴 for/in 執行順序
- varible 可以是 任意左值表示式
const o = { x: 1, y: 2, z: 3 },
a = [];
let i = 0;
for (a[i++] in o);
console.log(a);
// [ 'x', 'y', 'z' ]
複製程式碼
跳轉標籤
跳轉標籤是一個非常容易被忽略的語法(過於冷門),實際開發中幾乎看不到有人用,不過 在多迴圈巢狀時有奇效。
- 只有 break 和 continue 可以使用標籤
- 標籤的命名和規則和識別符號相同(字母、_、$ 開頭,後面可以跟數字)
- 標籤和變數是兩個名稱空間,不會互相沖突
- 內部的標籤不能和外部標籤重名
- 一個語句可以有多個標籤
- 使用標籤,可以讓 break 和 continue 跳過多層巢狀的迴圈體
- 標籤只在他定義的語句中有定義
使用標籤跳轉來快速結束查詢
const dataSource = new Array(100)
.fill(null)
.map((v, i) => new Array(i).fill(null).map((v, i) => new Array(i).fill(null)));
const TARGET = 'TARGET';
dataSource[50][30][20] = TARGET;
const l = dataSource.length;
let count = 0;
let result;
// 為了演示標籤,不寫遞迴
first: outter: parent: for (let i = 0; i < l; i++) {
count++;
const x = dataSource[i];
if (x === TARGET) {
result = [i];
break;
}
if (Array.isArray(x)) {
for (let j = 0; j < x.length; j++) {
count++;
const y = x[j];
if (y === TARGET) {
result = [i, j];
break first;
}
if (Array.isArray(y)) {
for (let k = 0; k < y.length; k++) {
count++;
const z = y[k];
if (z === TARGET) {
result = [i, j, k];
break first;
}
}
}
}
}
}
console.log(result);
// [50, 30, 20]
複製程式碼
如果不使用標籤,則需要在每個迴圈體的結尾再多做一次判斷來退出迴圈。
try/catch 注意點
try/catch 語句中哪怕是使用了 return、continue、break 等跳轉,也 一定會先執行完 finally 再執行跳轉到目標語句。
(function() {
try {
console.log('return');
return;
} catch (error) {
} finally {
console.log('finally');
}
})();
console.log('end');
// return
// finally
// end
複製程式碼
嚴格模式
晚上很多文章講的比較詳細,不細說
- 禁止使用 with
- 所有變數需要先宣告
- 呼叫的非方法函式中的 this 值為 undefined (可用於判斷瀏覽器是否支援嚴格模式)
- call 和 apply 呼叫函式時,this 值為傳入的第一個引數
- 只讀屬性賦值、不可擴充套件的物件建立新成員將報錯
- eval 不能再呼叫程式的上下文宣告變數、定義函式
- arguments 擁有引數的靜態副本,不會和實參共用引用
- delete 非法標識將、不可配置的屬性會報錯
- 物件直接量中定義多個同名屬性會報錯
- 函式存在多個同名引數會報錯
- 不允許使用八進位制直接量
- eval 和 arguments 被作為關鍵字,值不可修改
- 訪問 arguments.caller arguments.callee 、函式的 caller、arguments 會丟擲型別錯誤