轉載:http://blog.csdn.net/leoleocs
// 指示javascript引擎切換到嚴格模式。
'use strict';
//引入工具類包,有一些幫助函數可以使用,這裏主要使用的是格式化的部分。
var util = require('util');
// 控制檯對象構造函數
//@stdout 標準輸出對象
//@stderr 標準錯誤輸出對象
function Console(stdout, stderr) {
//檢查當前對象是否爲Console
if (!(this instanceof Console)) {
return new Console(stdout, stderr);
}
//檢查輸入參數, 確保輸入參數stdout對象上有write屬性,並且爲函數
// 也就是說,只要對象上有write屬性,都可以爲stdout對象
if (!stdout || !util.isFunction(stdout.write)) {
throw new TypeError('Console expects a writable stream instance');
}
// 如果stderr的參數沒有被指定,直接使用stdout參數
if (!stderr) {
stderr = stdout;
}
//定義屬性
var prop = {
writable: true,
enumerable: false,
configurable: true
};
// 屬性值
prop.value = stdout;
//爲Console對象定義_stdout 屬性
Object.defineProperty(this, '_stdout', prop);
// 屬性值
prop.value = stderr;
//爲Console對象定義_stderr 屬性
Object.defineProperty(this, '_stderr', prop);
// 屬性值
prop.value = Object.create(null);
//爲Console對象定義_times 屬性
Object.defineProperty(this, '_times', prop);
// bind the prototype functions to this Console instance
var keys = Object.keys(Console.prototype);
// 將原形方法上的屬性綁定到Console對象上。
for (var v = 0; v < keys.length; v++) {
var k = keys[v];
this[k] = this[k].bind(this);
}
}
//總結上述Console的構造函數,其做了下面幾步:
//step1: 檢查參數,確保參數合法,默認stderr用stdout
//step2: 爲Console對象定義_stdeout, _stderr 等屬性
//step3: 將原型總的屬性或者方法拷貝到Console對象上。
// 定義Console的原型方法log
Console.prototype.log = function() {
// 實質上就是調用_stdout 的write方法。手續需要格式化參數
this._stdout.write(util.format.apply(this, arguments) + '\n');
};
// 實質上info函數是log函數的別名
Console.prototype.info = Console.prototype.log;
// 定義Console的原型方法warn
Console.prototype.warn = function() {
// 實質上就是調用_stderr的write方法。需要格式化參數
this._stderr.write(util.format.apply(this, arguments) + '\n');
};
// 實質上error函數是warn函數的別名
Console.prototype.error = Console.prototype.warn;
// 直接輸出某個對象
Console.prototype.dir = function(object, options) {
// 注意使用的還是_stdout屬相上的write方法
// 不過在此前,其調用的工具類inspect方法去格式化具體的對象
// 這個函數可以用於輸出Javascript對象進行調試分析
this._stdout.write(util.inspect(object, util._extend({
customInspect: false
}, options)) + '\n');
};
// 時間函數, 計時開始函數
Console.prototype.time = function(label) {
// 在times空對象上加入label屬性,屬性值爲當前時間,
// 其實就是相當於開始計時函數
this._times[label] = Date.now();
};
// 時間函數, 計時結束函數,並且輸出時間
Console.prototype.timeEnd = function(label) {
//讀取開始時間
var time = this._times[label];
// 檢查是否有開始時間,如果沒有,直接拋出異常
if (!time) {
throw new Error('No such label: ' + label);
}
// 計算計時時間
var duration = Date.now() - time;
// 輸出計時時間
this.log('%s: %dms', label, duration);
};
// 輸出當前的調用堆棧信息
Console.prototype.trace = function trace() {
// TODO probably can to do this better with V8's debug object once that is
// exposed.
// 創建Error對象,並用全局函數Error.captureStackTrace來初始化
// 堆棧信息
var err = new Error;
err.name = 'Trace';
err.message = util.format.apply(this, arguments);
Error.captureStackTrace(err, trace);
// 利用error函數,也就是stderr屬性的write方法輸出
this.error(err.stack);
};
// 基本等同於assert.ok的使用
// 只有第一個參數爲假的時候,會有作用,也就是出錯
Console.prototype.assert = function(expression) {
if (!expression) {
// 獲取格式化的參數,除掉第一個爲假的表達式
var arr = Array.prototype.slice.call(arguments, 1);
// 只不過需要util.format格式化參數,也就是說,
//這裏面可以使用'%d', '%s'等。
require('assert').ok(false, util.format.apply(this, arr));
}
};
// 導出的對象本身就是一個新的Console對象,注意使用的參數爲
// process.stdout, process.stderr
// 所以,我們可以直接用下面的用法:
// var tmpConsole = require('console')
// tmpConsole.log('test %d', 0);
// 從官方文檔中,我們可以直接用全局的console對象。
module.exports = new Console(process.stdout, process.stderr);
// 導出Console的構造函數
//我們可以這麼用
// var Console = require('console').Console;
// var tmpConsole = new Console(process.stdout, process.stderr);
module.exports.Console = Console;
// 創建標準輸出對象到文件
var output = fs.createWriteStream('./stdout.log');
// 創建標準錯誤輸出對象到文件
var errorOutput = fs.createWriteStream('./stderr.log');
// 創建自己的Console對象
var logger = new Console(output, errorOutput);
var count = 5;
// 直接輸出到文件stdout.log中
logger.log('count: %d', count);