[TOC]
console對象是JavaScript的原生對象,它有點像Unix系統的標準輸出stdout和標準錯誤stderr,可以輸出各種信息用來調試程序,而且還提供了很多額外的方法,供開發者調用。它的常見用途有兩個。
* 顯示網頁代碼運行時的錯誤信息。
* 提供了一個命令行接口,用來與網頁代碼互動。
## 瀏覽器實現
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:調試JavaScript代碼。
* Timeline:查看各種網頁行為隨時間變化的情況。
* Profiles:查看網頁的性能情況,比如CPU和內存消耗。
* Audits:提供網頁優化的建議。
* Console:用來運行JavaScript命令。
這八個面板都有各自的用途,以下內容針對Console面板,又稱為控制臺。Console面板基本上就是一個命令行窗口,你可以在提示符下,鍵入各種命令。
下面介紹console對象提供的各種方法。
## console對象的方法
### log(),info(),debug()
console.log方法用于在console窗口輸出信息。它可以接受多個參數,將它們的結果連接起來輸出。
~~~
console.log("Hello World")
// Hello World
console.log("a","b","c")
// a b c
~~~
console.log方法會自動在每次輸出的結尾,添加換行符。
~~~
console.log(1);
console.log(2);
console.log(3);
// 1
// 2
// 3
~~~
如果第一個參數是格式字符串(使用了格式占位符),console.log方法將依次用后面的參數替換占位符,然后再進行輸出。
~~~
console.log(" %s + %s = %s", 1, 1, 2)
// 1 + 1 = 2
~~~
上面代碼中,console.log方法的第一個參數有三個占位符(%s),第二、三、四個參數會在顯示時,依次替換掉這個三個占位符。console.log方法支持的占位符有以下幾個,不同格式的數據必須使用對應格式的占位符。
* %s 字符串
* %d 整數
* %i 整數
* %f 浮點數
* %o 對象的鏈接
* %c CSS格式字符串
~~~
var number = 11 * 9;
var color = 'red';
console.log('%d %s balloons', number, color);
// 99 red balloons
~~~
上面代碼中,第二個參數是數值,對應的占位符是%d,第三個參數是字符串,對應的占位符是%s。
使用%c占位符時,對應的參數必須是CSS語句,用來對輸出內容進行CSS渲染。
~~~
console.log('%cThis text is styled!',
'color: #86CC00; background-color: blue; font-size: 20px; padding: 3px;'
)
~~~
上面代碼運行后,輸出的內容將顯示為藍底綠字。
log方法的兩種參數格式,可以結合在一起使用。
~~~
console.log(" %s + %s ", 1, 1, "= 2")
// 1 + 1 = 2
~~~
如果參數是一個對象,console.log會顯示該對象的值。
~~~
console.log({foo: 'bar'})
// Object {foo: "bar"}
console.log(Date)
// function Date() { [native code] }
~~~
上面代碼輸出Date對象的值,結果為一個構造函數。
console.info()和console.debug()都是console.log方法的別名,用法完全一樣。console.info方法會在輸出信息的前面,加上一個藍色圖標。
console對象的所有方法,都可以被覆蓋。因此,可以按照自己的需要,定義console.log方法。
~~~
["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方法,可以在顯示結果添加當前時間。
### warn(),error()
warn方法和error方法也是輸出信息,它們與log方法的不同之處在于,warn方法輸出信息時,在最前面加一個黃色三角,表示警告;error方法輸出信息時,在最前面加一個紅色的叉,表示出錯,同時會顯示錯誤發生的堆棧。其他用法都一樣。
~~~
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)。
### table()
對于某些復合類型的數據,console.table方法可以將其轉為表格顯示。
~~~
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" |
復合型數據轉為表格顯示的條件是,必須擁有主鍵。對于上面的數組來說,主鍵就是數字鍵。對于對象來說,主鍵就是它的最外層鍵。
~~~
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" |
### count()
count方法用于計數,輸出它被調用了多少次。
~~~
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方法就輸出執行次數。
該方法可以接受一個字符串作為參數,作為標簽,對執行次數進行分類。
~~~
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執行了一次。
### dir()
dir方法用來對一個對象進行檢查(inspect),并以易于閱讀和打印的格式顯示。
~~~
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對象的所有屬性。
~~~
console.dir(document.body)
~~~
### assert()
assert方法接受兩個參數,第一個參數是表達式,第二個參數是字符串。只有當第一個參數為false,才會輸出第二個參數,否則不會有任何結果。
~~~
// 實例
console.assert(true === false, "判斷條件不成立")
// Assertion failed: 判斷條件不成立
~~~
下面是另一個例子,判斷子節點的個數是否大于等于500。
~~~
console.assert(list.childNodes.length < 500, "節點個數大于等于500")
~~~
### time(),timeEnd()
這兩個方法用于計時,可以算出一個操作所花費的準確時間。
~~~
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窗口會顯示“計時器名稱: 所耗費的時間”。
### timeline(),timelineEnd(),timeStamp()
console.timeline和console.timelineEnd這兩個方法用于定義一個新的時間線,可以在Timeline面板查看。這兩個方法只有Chrome開發者工具支持。
~~~
console.timeline('Google Search');
// Do some work
console.timelineEnd('Google Search');
~~~
上面代碼定義了一個名稱叫做“Google Search”的時間線,在這個時間線里的所有事件的耗時,可以在Timeline面板中查看。
console.timeStamp方法用在上面兩個方法的中間,用于為時間線添加一個時間戳。時間戳的名字就是timeStamp方法的參數。
### profile(),profileEnd()
console.profile方法用來新建一個性能測試器(profile),它的參數是性能測試器的名字。
~~~
console.profile('p')
// Profile 'p' started.
~~~
console.profileEnd方法用來結束正在運行的性能測試器。
~~~
console.profileEnd()
// Profile 'p' finished.
~~~
打開瀏覽器的開發者工具,在profile面板中,可以看到這個性能調試器的運行結果。
### group(),groupend(),groupCollapsed()
console.group和console.groupend這兩個方法用于將顯示的信息分組。它只在輸出大量信息時有用,分在一組的信息,可以用鼠標折疊/展開。
~~~
console.group('Group One');
console.group('Group Two');
// some code
console.groupEnd(); // Group Two 結束
console.groupEnd(); // Group One 結束
~~~
console.groupCollapsed方法與console.group方法很類似,唯一的區別是該組的內容,在第一次顯示時是收起的(collapsed),而不是展開的。
~~~
console.groupCollapsed('Fetching Data');
console.log('Request Sent');
console.error('Error: Server not responding (500)');
console.groupEnd();
~~~
上面代碼只顯示一行”Fetching Data“,點擊后才會展開,顯示其中包含的兩行。
### trace(),clear()
console.trace方法顯示當前執行的代碼在堆棧中的調用路徑。
~~~
console.trace()
// console.trace()
// (anonymous function)
// InjectedScript._evaluateOn
// InjectedScript._evaluateAndWrap
// InjectedScript.evaluate
~~~
console.clear方法用于清除當前控制臺的所有輸出,將光標回置到第一行。
## 命令行API
在控制臺中,除了使用console對象,還可以使用一些控制臺自帶的命令行方法。
(1)$_
$_屬性返回上一個表達式的值。
~~~
2+2
// 4
$_
// 4
~~~
(2)$0 - $4
控制臺保存了最近5個在Elements面板選中的DOM元素,$0代表倒數第一個,$1代表倒數第二個,以此類推直到$4。
(3)$(selector)
$(selector)返回一個數組,包括特定的CSS選擇器匹配的所有DOM元素。該方法實際上是document.querySelectorAll方法的別名。
~~~
var images = $('img');
for (each in images) {
console.log(images[each].src);
}
~~~
上面代碼打印出網頁中所有img元素的src屬性。
(4)$$(selector)
$$(selector)返回一個選中的DOM對象,等同于document.querySelectorAll。
(5)$x(path)
$x(path)方法返回一個數組,包含匹配特定XPath表達式的所有DOM元素。
~~~
$x("//p[a]")
~~~
上面代碼返回所有包含a元素的p元素。
(6)inspect(object)
inspect(object)方法打開相關面板,并選中相應的元素:DOM元素在Elements面板中顯示,JavaScript對象在Profiles中顯示。
(7)getEventListeners(object)
getEventListeners(object)方法返回一個對象,該對象的成員為登記了回調函數的各種事件(比如click或keydown),每個事件對應一個數組,數組的成員為該事件的回調函數。
(8)keys(object),values(object)
keys(object)方法返回一個數組,包含特定對象的所有鍵名。
values(object)方法返回一個數組,包含特定對象的所有鍵值。
~~~
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方法用于停止監聽。
~~~
monitorEvents(window, "resize");
monitorEvents(window, ["resize", "scroll"])
~~~
上面代碼分別表示單個事件和多個事件的監聽方法。
~~~
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"
~~~
monitorEvents($("#msg"), "key");
~~~
上面代碼表示監聽所有key大類的事件。
(10)profile([name]),profileEnd()
profile方法用于啟動一個特定名稱的CPU性能測試,profileEnd方法用于結束該性能測試。
~~~
profile("My profile")
profileEnd("My profile")
~~~
(11)其他方法
命令行API還提供以下方法。
* clear()方法清除控制臺的歷史。
* copy(object)方法復制特定DOM元素到剪貼板。
* dir(object)方法顯示特定對象的所有屬性,是console.dir方法的別名。
* dirxml(object)方法顯示特定對象的XML形式,是console.dirxml方法的別名。
## debugger語句
debugger語句必須與除錯工具配合使用,如果沒有除錯工具,debugger語句不會產生任何結果。
在chrome瀏覽器中,當代碼運行到debugger指定的行時,就會暫停運行,自動打開console界面。它的作用類似于設置斷點。
~~~
for(var i = 0;i<5;i++){
console.log(i);
if (i===2) debugger;
}
~~~
上面代碼打印出0,1,2以后,就會暫停,自動打開console窗口,等待進一步處理。
## 移動端開發
(本節暫存此處)
### 模擬手機視口(viewport)
chrome瀏覽器的開發者工具,提供一個選項,可以模擬手機屏幕的顯示效果。
打開“設置”的Overrides面板,選擇相應的User Agent和Device Metrics選項。

User Agent可以使得當前瀏覽器發出手機瀏覽器的Agent字符串,Device Metrics則使得當前瀏覽器的視口變為手機的視口大小。這兩個選項可以獨立選擇,不一定同時選中。
### 模擬touch事件
我們可以在PC端模擬JavaScript的touch事件。
首先,打開chrome瀏覽器的開發者工具,選擇“設置”中的Overrides面板,勾選“Enable touch events”選項。

然后,鼠標就會觸發touchstart、touchmove和touchend事件。(此時,鼠標本身的事件依然有效。)
至于多點觸摸,必須要有支持這個功能的設備才能模擬,具體可以參考[Multi-touch web development](http://www.html5rocks.com/en/mobile/touch/)。
### 模擬經緯度
chrome瀏覽器的開發者工具,還可以模擬當前的經緯度數據。打開“設置”的Overrides面板,選中Override Geolocation選項,并填入相應經度和緯度數據。

### 遠程除錯
(1) Chrome for Android
Android設備上的Chrome瀏覽器支持USB除錯。PC端需要安裝Android SDK和Chrome瀏覽器,然后用usb線將手機和PC連起來,可參考[官方文檔](https://developers.google.com/chrome-developer-tools/docs/remote-debugging)。
(2) Opera
Opera瀏覽器的除錯環境Dragonfly支持遠程除錯([教程](http://www.codegeek.net/blog/2012/mobile-debugging-with-opera-dragonfly/))。
(3) Firefox for Android
參考[官方文檔](https://hacks.mozilla.org/2012/08/remote-debugging-on-firefox-for-android/)。
(4) Safari on iOS6
你可以使用Mac桌面電腦的Safari 6瀏覽器,進行遠程除錯([教程](http://www.mobilexweb.com/blog/iphone-5-ios-6-html5-developers))。
## Google Closure
(本節暫存此處)
Google Closure是Google提供的一個JavaScript源碼處理工具,主要用于壓縮和合并多個JavaScript腳本文件。
Google Closure使用Java語言開發,使用之前必須先安裝Java。然后,前往[官方網站](https://developers.google.com/closure/)進行下載,這里我們主要使用其中的編譯器(compiler)。
首先,查看使用幫助。
~~~
java -jar /path/to/closure/compiler.jar --help
~~~
直接在腳本命令后面跟上要合并的腳本,就能完成合并。
~~~
java -jar /path/to/closure/compiler.jar *.js
~~~
使用--js參數,可以確保按照參數的先后次序合并文件。
~~~
java -jar /path/to/closure/compiler.jar --js script1.js --js script2.js --js script3.js
~~~
但是,這樣的運行結果是將合并后的文件全部輸出到屏幕(標準輸出),因此需要使用--js_output_file參數,指定合并后的文件名。
~~~
java -jar /path/to/closure/compiler.jar --js script1.js --js script2.js --js script3.js --js_output_file scripts-compiled.js
~~~
## Javascript 性能測試
(本節暫存此處)
### 第一種做法
最常見的測試性能的做法,就是同一操作重復n次,然后計算每次操作的平均時間。
~~~
var totalTime,
start = new Date,
iterations = 6;
while (iterations--) {
// Code snippet goes here
}
// totalTime → the number of milliseconds it took to execute
// the code snippet 6 times
totalTime = new Date - start;
~~~
上面代碼的問題在于,由于計算機的性能不斷提高,如果只重復6次,很可能得到0毫秒的結果,即不到1毫秒,Javascript引擎無法測量。
### 第二種做法
另一種思路是,測試單位時間內完成了多少次操作。
~~~
var hz,
period,
startTime = new Date,
runs = 0;
do {
// Code snippet goes here
runs++;
totalTime = new Date - startTime;
} while (totalTime < 1000);
// convert ms to seconds
totalTime /= 1000;
// period → how long per operation
period = totalTime / runs;
// hz → the number of operations per second
hz = 1 / period;
// can be shortened to
// hz = (runs * 1000) / totalTime;
~~~
這種做法的注意之處在于,測試結構受外界環境影響很大,為了得到正確結構,必須重復多次。
## 參考鏈接
* 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)
- 第一章 導論
- 1.1 前言
- 1.2 為什么學習JavaScript?
- 1.3 JavaScript的歷史
- 第二章 基本語法
- 2.1 語法概述
- 2.2 數值
- 2.3 字符串
- 2.4 對象
- 2.5 數組
- 2.6 函數
- 2.7 運算符
- 2.8 數據類型轉換
- 2.9 錯誤處理機制
- 2.10 JavaScript 編程風格
- 第三章 標準庫
- 3.1 Object對象
- 3.2 Array 對象
- 3.3 包裝對象和Boolean對象
- 3.4 Number對象
- 3.5 String對象
- 3.6 Math對象
- 3.7 Date對象
- 3.8 RegExp對象
- 3.9 JSON對象
- 3.10 ArrayBuffer:類型化數組
- 第四章 面向對象編程
- 4.1 概述
- 4.2 封裝
- 4.3 繼承
- 4.4 模塊化編程
- 第五章 DOM
- 5.1 Node節點
- 5.2 document節點
- 5.3 Element對象
- 5.4 Text節點和DocumentFragment節點
- 5.5 Event對象
- 5.6 CSS操作
- 5.7 Mutation Observer
- 第六章 瀏覽器對象
- 6.1 瀏覽器的JavaScript引擎
- 6.2 定時器
- 6.3 window對象
- 6.4 history對象
- 6.5 Ajax
- 6.6 同域限制和window.postMessage方法
- 6.7 Web Storage:瀏覽器端數據儲存機制
- 6.8 IndexedDB:瀏覽器端數據庫
- 6.9 Web Notifications API
- 6.10 Performance API
- 6.11 移動設備API
- 第七章 HTML網頁的API
- 7.1 HTML網頁元素
- 7.2 Canvas API
- 7.3 SVG 圖像
- 7.4 表單
- 7.5 文件和二進制數據的操作
- 7.6 Web Worker
- 7.7 SSE:服務器發送事件
- 7.8 Page Visibility API
- 7.9 Fullscreen API:全屏操作
- 7.10 Web Speech
- 7.11 requestAnimationFrame
- 7.12 WebSocket
- 7.13 WebRTC
- 7.14 Web Components
- 第八章 開發工具
- 8.1 console對象
- 8.2 PhantomJS
- 8.3 Bower:客戶端庫管理工具
- 8.4 Grunt:任務自動管理工具
- 8.5 Gulp:任務自動管理工具
- 8.6 Browserify:瀏覽器加載Node.js模塊
- 8.7 RequireJS和AMD規范
- 8.8 Source Map
- 8.9 JavaScript 程序測試
- 第九章 JavaScript高級語法
- 9.1 Promise對象
- 9.2 有限狀態機
- 9.3 MVC框架與Backbone.js
- 9.4 嚴格模式
- 9.5 ECMAScript 6 介紹
- 附錄
- 10.1 JavaScript API列表
- 草稿一:函數庫
- 11.1 Underscore.js
- 11.2 Modernizr
- 11.3 Datejs
- 11.4 D3.js
- 11.5 設計模式
- 11.6 排序算法
- 草稿二:jQuery
- 12.1 jQuery概述
- 12.2 jQuery工具方法
- 12.3 jQuery插件開發
- 12.4 jQuery.Deferred對象
- 12.5 如何做到 jQuery-free?
- 草稿三:Node.js
- 13.1 Node.js 概述
- 13.2 CommonJS規范
- 13.3 package.json文件
- 13.4 npm模塊管理器
- 13.5 fs 模塊
- 13.6 Path模塊
- 13.7 process對象
- 13.8 Buffer對象
- 13.9 Events模塊
- 13.10 stream接口
- 13.11 Child Process模塊
- 13.12 Http模塊
- 13.13 assert 模塊
- 13.14 Cluster模塊
- 13.15 os模塊
- 13.16 Net模塊和DNS模塊
- 13.17 Express框架
- 13.18 Koa 框架