# JavaScript 入門課程 - 第四章 語法專題 4-4 console 物件與控制台
[竹白記事本](https://chupainotebook.blogspot.com/),學習筆記整理 2019/01/19。
###### tags: `JavaScript 入門課程` `JavaScript` `JavaScript 入門課程 - 第四章 語法專題`
>學習書本:
>[JavaScript 教程電子書|作者:阮一峰老師](https://wangdoc.com/javascript/index.html)
「JavaScript 教程」是由阮一峰老師所撰寫的,並且授權方式為「知識共享署名-相同方式共享3.0協議」,非常適合初學者當作 JavaScript 語言的入門課程。
## [目錄](https://hackmd.io/zZe_oRgfQp6YFboDCVAvpg)
* Ch4 語法專題
* [4-1 資料類型的轉換](https://hackmd.io/s/rJxPLplQE)
* [4-2 錯誤處理機制](https://hackmd.io/s/SkgCd6xX4)
* [4-3 編程風格](https://hackmd.io/s/SJGgKTgQE)
* [4-4 console 物件與控制台](https://hackmd.io/s/Byw-KpxQ4)
# 4-4 console 物件與控制台
## 1. console 物件
`console` 對像是 JavaScript 的原生物件,它有點像 Unix 系統的標準輸出 `stdout` 和標準錯誤 `stderr`,可以輸出各種信息到控制台,並且還提供了很多有用的輔助方法。
`console` 的常見用途有兩個。
- 調試程序,顯示網頁代碼運行時的錯誤信息。
- 提供了一個命令行接口,用來與網頁代碼互動。
`console` 物件的瀏覽器實現,包含在瀏覽器自帶的開發工具之中。以 Chrome 瀏覽器的**開發者工具**(Developer Tools)為例,可以使用下面三種方法的打開它。
1. 按F12 或者 `Control + Shift + i`(PC)/ `Alt + Command + i`(Mac)。
2. 瀏覽器菜單選擇**工具/開發者工具**。
3. 在一個頁面元素上,打開右鍵菜單,選擇其中的**Inspect Element**。
打開開發者工具以後,頂端有多個面板。
- **Elements**:查看網頁的 HTML 源碼和CSS 代碼。
- **Resources**:查看網頁加載的各種資源文件(比如代碼文件、字體文件CSS 文件等),以及在硬盤上創建的各種內容(比如本地緩存、Cookie、Local Storage等)。
- **Network**:查看網頁的 HTTP 通信情況。
- **Sources**:查看網頁加載的腳本源碼。
- **Timeline**:查看各種網頁行為隨時間變化的情況。
- **Performance**:查看網頁的性能情況,比如 CPU 和記憶體消耗。
- **Console**:用來運行 JavaScript 命令。
這些面板都有各自的用途,以下只介紹 `Console` 面板(又稱為控制台)。
`Console`面板基本上就是一個命令行窗口,你可以在提示符下,鍵入各種命令。
## 2. console 物件的靜態方法
`console` 物件提供的各種靜態方法,用來與控制台窗口互動。
### 2.1 console.log(),console.info(),console.debug()
`console.log` 方法用於在控制台輸出信息。它可以接受一個或多個參數,將它們連接起來輸出。
```javascript
console.log('Hello World')
// Hello World
console.log('a', 'b', 'c')
// abc
```
`console.log` 方法會自動在每次輸出的結尾,添加換行符。
```javascript
console.log(1);
console.log(2);
console.log(3);
// 1
// 2
// 3
```
如果第一個參數是格式字串(使用了格式佔位符),`console.log` 方法將依次用後面的參數替換佔位符,然後再進行輸出。
```javascript
console.log(' %s + %s = %s', 1, 1, 2)
// 1 + 1 = 2
```
上面代碼中,`console.log` 方法的第一個參數有三個佔位符(`%s`),第二、三、四個參數會在顯示時,依次替換掉這個三個佔位符。
`console.log` 方法支持以下佔位符,不同型別的資料必須使用對應的佔位符。
- `%s` 字串
- `%d` 整數
- `%i` 整數
- `%f` 浮點數
- `%o` 物件的鏈接
- `%c` CSS 格式字串
```javascript
var number = 11 * 9;
var color = 'red';
console.log('%d %s balloons', number, color);
// 99 red balloons
```
上面代碼中,第二個參數是數值,對應的佔位符是 `%d`,第三個參數是字串,對應的佔位符是 `%s`。
使用 `%c` 佔位符時,對應的參數必須是CSS 代碼,用來對輸出內容進行CSS 渲染。
```javascript
console.log(
'%cThis text is styled!',
'color: red; background: yellow; font-size: 24px;'
)
```
上面代碼運行後,輸出的內容將顯示為黃底紅字。
`console.log` 方法的兩種參數格式,可以結合在一起使用。
```javascript
console.log(' %s + %s ', 1, 1, '= 2')
// 1 + 1 = 2
```
如果參數是一個物件,`console.log` 會顯示該物件的值。
```javascript
console.log({foo: 'bar'})
// Object {foo: "bar"}
console.log(Date)
// function Date() { [native code] }
```
上面代碼輸出 `Date` 物件的值,結果為一個建構式。
`console.info` 是 `console.log` 方法的別名,用法完全一樣。只不過 `console.info` 方法會在輸出信息的前面,加上一個藍色圖標。
`console.debug` 方法與 `console.log` 方法類似,會在控制台輸出調試信息。但是,默認情況下,`console.debug` 輸出的信息不會顯示,只有在打開顯示級別在 `verbose` 的情況下,才會顯示。
`console` 物件的所有方法,都可以被覆蓋。因此,可以按照自己的需要,定義 `console.log` 方法。
```javascript
['log', 'info', 'warn', 'error'].forEach(function(method) {
console[method] = console[method].bind(
console,
new Date().toISOString()
);
});
console.log("出錯了!");
// 2014-05-18T09:00.000Z 出錯了!
```
上面代碼表示,使用自定義的 `console.log` 方法,可以在顯示結果添加當前時間。
### 2.2 console.warn(),console.error()
`warn` 方法和 `error` 方法也是在控制台輸出信息,它們與 `log` 方法的不同之處在於,`warn` 方法輸出信息時,在最前面加一個黃色三角,表示警告;`error` 方法輸出信息時,在最前面加一個紅色的叉,表示出錯。同時,還會高亮顯示輸出文字和錯誤發生的堆疊。其他方面都一樣。
```javascript
console.error('Error: %s (%i)', 'Server is not responding', 500)
// Error: Server is not responding (500)
console.warn('Warning! Too few nodes (%d)', document.childNodes.length)
// Warning! Too few nodes (1)
```
可以這樣理解,`log` 方法是寫入標準輸出(`stdout`),`warn` 方法和 `error` 方法是寫入標準錯誤(`stderr`)。
### 2.3 console.table()
對於某些複合型別的資料,`console.table` 方法可以將其轉為表格顯示。
```javascript
var languages = [
{ name: "JavaScript", fileExtension: ".js" },
{ name: "TypeScript", fileExtension: ".ts" },
{ name: "CoffeeScript", fileExtension: ".coffee" }
];
console.table(languages);
```
上面代碼的 `language` 變數,轉為表格顯示如下:
(index)|name|fileExtension
-------|----|-------------
0|"JavaScript"|".js"
1|"TypeScript"|".ts"
2|"CoffeeScript"|".coffee"
下面是顯示表格內容的例子:
```javascript
var languages = {
csharp: { name: "C#", paradigm: "object-oriented" },
fsharp: { name: "F#", paradigm: "functional" }
};
console.table(languages);
```
上面代碼的 `language`,轉為表格顯示如下:
(index)|name|paradigm
-------|----|--------
csharp|"C#"|"object-oriented"
fsharp|"F#"|"functional"
### 2.4 console.count()
`count` 方法用於計數,輸出它被呼叫了多少次。
```javascript
function greet(user) {
console.count();
return 'hi ' + user;
}
greet('bob')
// : 1
// "hi bob"
greet('alice')
// : 2
// "hi alice"
greet('bob')
// : 3
// "hi bob"
```
上面代碼每次呼叫 `greet` 函數,內部的 `console.count` 方法就輸出執行次數。
該方法可以接受一個字串作為參數,作為標籤,對執行次數進行分類。
```javascript
function greet(user) {
console.count(user);
return "hi " + user;
}
greet('bob')
// bob: 1
// "hi bob"
greet('alice')
// alice: 1
// "hi alice"
greet('bob')
// bob: 2
// "hi bob"
```
上面代碼根據參數的不同,顯示 `bob` 執行了兩次,`alice` 執行了一次。
### 2.5 console.dir(),console.dirxml()
`dir` 方法用來對一個物件進行檢查(inspect),並以易於閱讀和打印的格式顯示。
```javascript
console.log({f1: 'foo', f2: 'bar'})
// Object {f1: "foo", f2: "bar"}
console.dir({f1: 'foo', f2: 'bar'})
// Object
// f1: "foo"
// f2: "bar"
// __proto__: Object
```
上面代碼顯示 `dir` 方法的輸出結果,比 `log` 方法更易讀,信息也更豐富。
該方法對於輸出 DOM 物件非常有用,因為會顯示 DOM 物件的所有屬性。
```javascript
console.dir(document.body)
```
Node 環境之中,還可以指定以代碼高亮的形式輸出。
```javascript
console.dir(obj, {colors: true})
```
`dirxml` 方法主要用於以目錄樹的形式,顯示 DOM 節點。
```javascript
console.dirxml(document.body)
```
如果參數不是 DOM 節點,而是普通的 JavaScript 物件,`console.dirxml` 等同於 `console.dir`。
```javascript
console.dirxml([1, 2, 3])
// 等同於
console.dir([1, 2, 3])
```
### 2.6 console.assert()
`console.assert` 方法主要用於程序運行程序中,進行條件判斷,如果不滿足條件,就顯示一個錯誤,但不會中斷程序執行。這樣就相當於提示用戶,內部狀態不正確。
它接受兩個參數,第一個參數是表達式,第二個參數是字串。只有當第一個參數為 `false`,才會提示有錯誤,在控制台輸出第二個參數,否則不會有任何結果。
```javascript
console.assert(false, '判斷條件不成立')
// Assertion failed: 判斷條件不成立
// 相當於
try {
if (!false) {
throw new Error('判斷條件不成立');
}
} catch(e) {
console.error(e);
}
```
下面是一個例子,判斷子節點的個數是否大於等於 500。
```javascript
console.assert(list.childNodes.length < 500, '節點個數大於等於500')
```
上面代碼中,如果符合條件的節點小於 500 個,不會有任何輸出;只有大於等於 500 時,才會在控制台提示錯誤,並且顯示指定文本。
### 2.7 console.time(),console.timeEnd()
這兩個方法用於計時,可以算出一個操作所花費的準確時間。
```javascript
console.time('Array initialize');
var array= new Array(1000000);
for (var i = array.length - 1; i >= 0; i--) {
array[i] = new Object();
};
console.timeEnd('Array initialize');
// Array initialize: 1914.481ms
```
`time` 方法表示計時開始,`timeEnd` 方法表示計時結束。它們的參數是計時器的名稱。呼叫 `timeEnd` 方法之後,控制台會顯示**計時器名稱: 所耗費的時間**。
### 2.8 console.group(),console.groupEnd(),console.groupCollapsed()
`console.group` 和 `console.groupEnd` 這兩個方法用於將顯示的信息分組。它只在輸出大量信息時有用,分在一組的信息,可以用鼠標折疊/展開。
```javascript
console.group('一級分組');
console.log('一級分組的內容');
console.group('二級分組');
console.log('二級分組的內容');
console.groupEnd(); // 二級分組結束
console.groupEnd(); // 一級分組結束
```
上面代碼會將**二級分組**顯示在**一級分組**內部,並且**一級分組**和**二級分組**前面都有一個折疊符號,可以用來折疊本級的內容。
`console.groupCollapsed` 方法與 `console.group` 方法很類似,唯一的區別是該組的內容,在第一次顯示時是收起的(collapsed),而不是展開的。
```javascript
console.groupCollapsed('Fetching Data');
console.log('Request Sent');
console.error('Error: Server not responding (500)');
console.groupEnd();
```
上面代碼只顯示一行**Fetching Data**,點擊後才會展開,顯示其中包含的兩行。
### 2.9 onsole.trace(),console.clear()
`console.trace`方法顯示當前執行的代碼在堆疊中的呼叫路徑。
```javascript
console.trace()
// console.trace()
// (anonymous function)
// InjectedScript._evaluateOn
// InjectedScript._evaluateAndWrap
// InjectedScript.evaluate
```
`console.clear` 方法用於清除當前控制台的所有輸出,將光標回置到第一行。如果用戶選中了控制台的 **Preserve log** 選項,`console.clear` 方法將不起作用。
## 3 控制台命令行API
瀏覽器控制台中,除了使用 `console` 物件,還可以使用一些控制台自帶的命令行方法。
**(1)** `$_`
`$_` 屬性返回上一個表達式的值。
```javascript
2 + 2
// 4
$_
// 4
```
**(2)**`$0` - `$4`
控制台保存了最近5個在Elements 面板選中的DOM 元素,`$0` 代表倒數第一個(最近一個),`$1` 代表倒數第二個,以此類推直到 `$4`。
**(3)**`$(selector)`
`$(selector)` 返回第一個匹配的元素,等同於 `document.querySelector()`。注意,如果頁面腳本對 `$` 有定義,則會覆蓋原始的定義。比如,頁面裡面有 jQuery,控制台執行 `$(selector)` 就會採用 jQuery 的實現,返回一個陣列。
**(4)**`$$(selector)`
`$$(selector)` 返回選中的DOM 物件,等同於 `document.querySelectorAll`。
**(5)**`$x(path)`
`$x(path)` 方法返回一個陣列,包含匹配特定 XPath 表達式的所有 DOM 元素。
```javascript
$x("//p[a]")
```
上面代碼返回所有包含 `a` 元素的 `p` 元素。
**(6)**`inspect(object)`
`inspect(object)` 方法打開相關面板,並選中相應的元素,顯示它的細節。DOM 元素在 `Elements` 面板中顯示,比如`inspect(document)` 會在Elements 面板顯示 `document` 元素。JavaScript 對像在控制檯面板 `Profiles` 面板中顯示,比如 `inspect(window)`。
**(7)**`getEventListeners(object)`
`getEventListeners(object)` 方法返回一個物件,該物件的成員為 `object` 登記了回調函數的各種事件(比如 `click` 或 `keydown`),每個事件對應一個陣列,陣列的成員為該事件的回調函數。
**(8)**`keys(object)`,`values(object)`
`keys(object)` 方法返回一個陣列,包含 `object` 的所有鍵名。
`values(object)` 方法返回一個陣列,包含 `object` 的所有鍵值。
```javascript
var o = {'p1': 'a', 'p2': 'b'};
keys(o)
// ["p1", "p2"]
values(o)
// ["a", "b"]
```
**(9)**`monitorEvents(object[, events]) ,unmonitorEvents(object[, events])`
`monitorEvents(object[, events])` 方法監聽特定對像上發生的特定事件。事件發生時,會返回一個 `Event` 物件,包含該事件的相關信息。`unmonitorEvents` 方法用於停止監聽。
```javascript
monitorEvents(window, "resize");
monitorEvents(window, ["resize", "scroll"])
```
上面代碼分別表示單個事件和多個事件的監聽方法。
```javascript
monitorEvents($0, 'mouse');
unmonitorEvents($0, 'mousemove');
```
上面代碼表示如何停止監聽。
`monitorEvents` 允許監聽同一大類的事件。所有事件可以分成四個大類。
- mouse:"mousedown", "mouseup", "click", "dblclick", "mousemove", "mouseover", "mouseout", "mousewheel"
- key:"keydown", "keyup", "keypress", "textInput"
- touch:"touchstart", "touchmove", "touchend", "touchcancel"
- control:"resize", "scroll", "zoom", "focus", "blur", "select", "change", "submit", "reset"
```javascript
monitorEvents($("#msg"), "key");
```
上面代碼表示監聽所有 `key` 大類的事件。
**(10)**其他方法
命令行 API 還提供以下方法:
- `clear()`:清除控制台的歷史。
- `copy(object)`:複製特定DOM 元素到剪貼板。
- `dir(object)`:顯示特定物件的所有屬性,是 `console.dir` 方法的別名。
- `dirxml(object)`:顯示特定物件的XML 形式,是 `console.dirxml` 方法的別名。
## 4. debugger 陳述句
`debugger` 陳述句主要用於除錯,作用是設置斷點。如果有正在運行的除錯工具,程序運行到 `debugger` 陳述句時會自動停下。如果沒有除錯工具,`debugger` 陳述句不會產生任何結果,JavaScript 引擎自動跳過這一句。
Chrome 瀏覽器中,當代碼運行到 `debugger` 陳述句時,就會暫停運行,自動打開腳本源碼界面。
```javascript
for(var i = 0; i < 5; i++){
console.log(i);
if (i === 2) debugger;
}
```
上面代碼打印出 0,1,2 以後,就會暫停,自動打開源碼界面,等待進一步處理。
---
>下個章節:[Ch5 標準庫](https://hackmd.io/s/HyG_GJX74)