我能否在javascript中扩展console对象(以重新定向日志记录)?

31

是否可以扩展控制台对象?

我尝试了以下代码:

Console.prototype.log = function(msg){
    Console.prototype.log.call(msg);
    alert(msg);
}

但这个方法没有起作用。我想通过像log4javascript这样的框架向控制台对象添加额外的日志记录,并在我的代码中仍然使用标准的控制台对象(在log4javascript不可用的情况下)。

先感谢您!


5
为什么您要扩展原型对象而不是扩展Console对象本身?您是否曾调用过new Console()? - biziclop
6个回答

47

尝试以下方法:

(function() {
    var exLog = console.log;
    console.log = function(msg) {
        exLog.apply(this, arguments);
        alert(msg);
    }
})()

5

这实际上是其他一些人提供的相同解决方案,但我认为这是实现这一目标最优雅和最少hacky的方法。展开语法(...args)确保没有一个参数会丢失。

var _console={...console}

console.log = function(...args) {
    var msg = {...args}[0];
    //YOUR_CODE
    _console.log(...args);
}

很好地使用了展开/剩余语法,但其实并不需要,有一种更短的方式可以支持IE并且不会覆盖上面的原型。 - Mister SirCode

4
你也可以这样添加日志时间:
使用Moment.js或者使用New Date()代替moment。
var oldConsole = console.log;
console.log = function(){
    var timestamp = "[" + moment().format("YYYY-MM-DD HH:mm:ss:SSS") + "] ";
    Array.prototype.unshift.call(arguments, timestamp);
    oldConsole.apply(this, arguments);
};

这无法正常工作,因为它会生成“moment未定义”的错误。 - nbsp
你需要使用npm install moment来安装moment。 - Nitesh singh
2
好的,我猜可以这样做,但我更喜欢本地解决方案。例如,NPM是需要存在的“另一件”事情。 - nbsp

2

针对ECMAScript 2015及更高版本

您可以使用新的代理(proxy)功能来“劫持”全局的console.log,该功能是从ECMAScript 2015标准中引入的。

源代码

'use strict';

class Mocker {
  static mockConsoleLog() {
    Mocker.oldGlobalConsole = window.console;

    window.console = new Proxy(window.console, {
      get(target, property) {
        if (property === 'log') {
          return function(...parameters) {
            Mocker.consoleLogReturnValue = parameters.join(' ');
          }
        }

        return target[property];
      }
    });
  }

  static unmockConsoleLog() {
    window.console = Mocker.oldGlobalConsole;
  }
}

Mocker.mockConsoleLog();

console.log('hello'); // nothing happens here

Mocker.unmockConsoleLog();

if (Mocker.consoleLogReturnValue === 'hello') {
  console.log('Hello world!'); // Hello world!
  alert(Mocker.consoleLogReturnValue);
  // anything you want to do with the console log return value here...
}

在线演示

Repl.it提供了在线演示。

Node.js用户注意

如果你在使用Node.js,可以使用此源代码,并将window.console替换为global.console以正确引用控制台对象(当然,要去掉alert调用)。实际上,我最初是在Node.js上编写并测试了这段代码。

注:原文中的"Original Answer"翻译成中文后就是"最初的回答"。

2
与上面使用6行覆写的答案相比,我认为这对于一个简单的函数重写来说有些过度了。 - Mister SirCode
不要使用代理来劫持单个属性。 - Bergi

1
// console aliases and verbose logger - console doesnt prototype
var c = console;
c.l = c.log,
c.e = c.error,
c.v = c.verbose = function() {
    if (!myclass || !myclass.verbose) // verbose switch
        return;
    var args = Array.prototype.slice.call(arguments); // toArray
    args.unshift('Verbose:');
    c.l.apply(this, args); // log
};

// you can then do
var myclass = new myClass();
myclass.prototype.verbose = false;
// generally these calls would be inside your class
c.v('1 This will NOT log as verbose == false');
c.l('2 This will log');
myclass.verbose = true;
c.v('3 This will log');

我注意到nitesh使用Array.prototype.unshift.call的方法是添加“Verbose:”标签的更好方式。

0

您可以使用以下方法覆盖console.log函数的默认行为,下面的示例演示了如何使用重写的函数记录行号。

let line = 0;
const log = console.log;
console.log = (...data) => log(`${++line} ===>`, ...data)

console.log(11, 1, 2)
console.log(11, 1, 'some')


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接