# console 對象與控制臺
## console 對象
`console`對象是 JavaScript 的原生對象,它有點像 Unix 系統的標準輸出`stdout`和標準錯誤`stderr`,可以輸出各種信息到控制臺,并且還提供了很多有用的輔助方法。
`console`的常見用途有兩個。
- 調試程序,顯示網頁代碼運行時的錯誤信息。
- 提供了一個命令行接口,用來與網頁代碼互動。
`console`對象的瀏覽器實現,包含在瀏覽器自帶的開發工具之中。以 Chrome 瀏覽器的“開發者工具”(Developer Tools)為例,可以使用下面三種方法的打開它。
1. 按 F12 或者`Control + Shift + i`(PC)/ `Command + Option + i`(Mac)。
2. 瀏覽器菜單選擇“工具/開發者工具”。
3. 在一個頁面元素上,打開右鍵菜單,選擇其中的“Inspect Element”。
打開開發者工具以后,頂端有多個面板。
- **Elements**:查看網頁的 HTML 源碼和 CSS 代碼。
- **Resources**:查看網頁加載的各種資源文件(比如代碼文件、字體文件 CSS 文件等),以及在硬盤上創建的各種內容(比如本地緩存、Cookie、Local Storage等)。
- **Network**:查看網頁的 HTTP 通信情況。
- **Sources**:查看網頁加載的腳本源碼。
- **Timeline**:查看各種網頁行為隨時間變化的情況。
- **Performance**:查看網頁的性能情況,比如 CPU 和內存消耗。
- **Console**:用來運行 JavaScript 命令。
這些面板都有各自的用途,以下只介紹`Console`面板(又稱為控制臺)。
`Console`面板基本上就是一個命令行窗口,你可以在提示符下,鍵入各種命令。
## console 對象的靜態方法
`console`對象提供的各種靜態方法,用來與控制臺窗口互動。
### console.log(),console.info(),console.debug()
`console.log`方法用于在控制臺輸出信息。它可以接受一個或多個參數,將它們連接起來輸出。
```javascript
console.log('Hello World')
// Hello World
console.log('a', 'b', 'c')
// a b c
```
`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`方法,可以在顯示結果添加當前時間。
### 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`)。
### 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"
### 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`執行了一次。
### 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])
```
### 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時,才會在控制臺提示錯誤,并且顯示指定文本。
### 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`方法之后,控制臺會顯示“計時器名稱: 所耗費的時間”。
### 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“,點擊后才會展開,顯示其中包含的兩行。
### console.trace(),console.clear()
`console.trace`方法顯示當前執行的代碼在堆棧中的調用路徑。
```javascript
console.trace()
// console.trace()
// (anonymous function)
// InjectedScript._evaluateOn
// InjectedScript._evaluateAndWrap
// InjectedScript.evaluate
```
`console.clear`方法用于清除當前控制臺的所有輸出,將光標回置到第一行。如果用戶選中了控制臺的“Preserve log”選項,`console.clear`方法將不起作用。
## 控制臺命令行 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`方法的別名。
## 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以后,就會暫停,自動打開源碼界面,等待進一步處理。
## 參考鏈接
- Chrome Developer Tools, [Using the Console](https://developers.google.com/chrome-developer-tools/docs/console)
- Matt West, [Mastering The Developer Tools Console](http://blog.teamtreehouse.com/mastering-developer-tools-console)
- Firebug Wiki, [Console API](https://getfirebug.com/wiki/index.php/Console_API)
- Axel Rauschmayer, [The JavaScript console API](http://www.2ality.com/2013/10/console-api.html)
- Marius Schulz, [Advanced JavaScript Debugging with console.table()](http://blog.mariusschulz.com/2013/11/13/advanced-javascript-debugging-with-consoletable)
- Google Developer, [Command Line API Reference](https://developers.google.com/chrome-developer-tools/docs/commandline-api)
- 前言
- 入門篇
- 導論
- 歷史
- 基本語法
- 數據類型
- 概述
- null,undefined 和布爾值
- 數值
- 字符串
- 對象
- 函數
- 數組
- 運算符
- 算術運算符
- 比較運算符
- 布爾運算符
- 二進制位運算符
- 其他運算符,運算順序
- 語法專題
- 數據類型的轉換
- 錯誤處理機制
- 編程風格
- console 對象與控制臺
- 標準庫
- Object 對象
- 屬性描述對象
- Array 對象
- 包裝對象
- Boolean 對象
- Number 對象
- String 對象
- Math 對象
- Date 對象
- RegExp 對象
- JSON 對象
- 面向對象編程
- 實例對象與 new 命令
- this 關鍵字
- 對象的繼承
- Object 對象的相關方法
- 嚴格模式
- 異步操作
- 概述
- 定時器
- Promise 對象
- DOM
- 概述
- Node 接口
- NodeList 接口,HTMLCollection 接口
- ParentNode 接口,ChildNode 接口
- Document 節點
- Element 節點
- 屬性的操作
- Text 節點和 DocumentFragment 節點
- CSS 操作
- Mutation Observer API
- 事件
- EventTarget 接口
- 事件模型
- Event 對象
- 鼠標事件
- 鍵盤事件
- 進度事件
- 表單事件
- 觸摸事件
- 拖拉事件
- 其他常見事件
- GlobalEventHandlers 接口
- 瀏覽器模型
- 瀏覽器模型概述
- window 對象
- Navigator 對象,Screen 對象
- Cookie
- XMLHttpRequest 對象
- 同源限制
- CORS 通信
- Storage 接口
- History 對象
- Location 對象,URL 對象,URLSearchParams 對象
- ArrayBuffer 對象,Blob 對象
- File 對象,FileList 對象,FileReader 對象
- 表單,FormData 對象
- IndexedDB API
- Web Worker
- 附錄:網頁元素接口
- a
- img
- form
- input
- button
- option
- video,audio