如何安全地包装`console.log`?

时间:2012-01-09 08:32:32

标签: javascript internet-explorer console logging wrapper

假设我想在某些合法的生产原因中包含对console.log的一些调用,比如像单元测试工具那样。显然,如果浏览器没有consoleno console is present,我不希望这会抛出过早的异常。

创建简单的log函数以将内容记录到控制台的最佳方法是什么,或者如果没有控制台,则默默地失败而没有错误?

上述相关问题的接受答案:

var log = Function.prototype.bind.call(console.log, console);
log.apply(console, ["this", "is", "a", "test"]);

这个log函数是否可以在IE上正常调用,这里使用apply只是为了表明它是可能的?并且,我从链接的问题中假设,如果IE的控制台在运行时关闭,这将失败,因此即使在控制台打开后,log也无法工作,对吗?如果这是错的,有人可以解释它是如何工作的吗?

ycombinator article似乎相关。他们是在讨论与上面链接的问题相同的IE行为吗?

Function.prototype.apply.apply(console.log, [console, arguments]);
     

适用于IE9破解的console.log和其他供应商的常规console.log。   与使用Array.prototype.slice将参数转换为实数组相同的黑客。

这在我的Chrome控制台中运行良好。

function echo(){
  Function.prototype.apply.apply(console.log, [console, arguments]);
}

简化为:

function echo(){
  Function.apply.call(console.log, console, arguments);
}

添加支票并返回:

function echo(){
  return window.console && console.log &&
         Function.apply.call(console.log, console, arguments);
}

上面的例子对我来说足够了。不过,我手头没有IE来测试它。这是安全包装console.log的合理方法吗?


更多问题

按照以下导航答案中的链接,我们会看到代码:

Function.prototype.call.call(console.log, console,
    Array.prototype.slice.call(arguments));

在这种情况下,将arguments转换为数组的目的是什么?我想如果你不这样做,它必须在某些浏览器中失败?并且,除了歌剧奇怪的行为和无控制台的浏览器之外,这样的东西不应该适用于其他所有浏览器吗? prototype是否有助于上述示例中的目的,或者我们只是迂腐...... Function.call.callObject.call.call或者isNaN.call.call似乎也很有用Function.prototype.call.call为{{1}}。

10 个答案:

答案 0 :(得分:20)

包装器的问题在于它们会混淆日志消息源的文件名和行号。

简单的IE7及以下垫片,为其他浏览器保留行号:

/* console shim*/
(function () {
    var f = function () {};
    if (!window.console) {
        window.console = {
            log:f, info:f, warn:f, debug:f, error:f
        };
    }
}());

答案 1 :(得分:16)

抱歉,我的帖子中有个错误。不知道我是怎么错过的。

创建全局控制台对象的正确方法(如果不存在):

if (typeof console === "undefined"){
    console={};
    console.log = function(){
        return;
    }
}

答案 2 :(得分:7)

  

这个日志功能可以在IE上正常调用,在这里使用apply只是为了表明它是可能的吗?

是的,是的。这个特定的例子直接针对“它是一个真正的函数”链接问题的一部分。

  

并且,我从链接的问题中假设,如果IE的控制台在运行时关闭,这将失败,因此即使在控制台打开后,日志也无法正常工作,对吗?

正确。正如我在该问题的答案中所解释的,console对象在第一次为特定选项卡打开开发人员工具之前不会公开。大多数开发人员使用控制台垫片,在这种情况下,Function#bind方法有点过时,因为您也可以使用Function#apply.apply方法。

  

在这种情况下,将参数转换为数组的目的是什么?

没有一个,这是多余的。除非它是自定义 log 实现,否则开发人员可能有理由将参数对象转换为数组。

  

在上面的例子中原型是否有用,或者我们只是迂腐...

嗯,是的,不是。某些开发人员可能无意中将Function.call更改为自定义函数或值。当然,他们也可以打破Function.prototype.call,但这不太可能偶然发生。

答案 3 :(得分:6)

我喜欢使用:

'console' in window && console.log("Boom!");

它适用于所有浏览器,易于理解。

答案 4 :(得分:3)

尝试使用下面的代码段...(这是我首选的方法,因为它使您独立于window.console)

var logger = (function (c) {
    "use strict";
    var m = {
        log: function (a, t) {
            if (!c) { return; /* return or call your custom function here */ }
            var l = c.log,
                f = t === undefined ? l : (this.__dict__[t] || l);
            f.apply(c, a)
        },
        __dict__: {
            "trace": c.trace,
            "debug": c.debug,
            "info": c.info,
            "warn": c.warn,
            "error": c.error
        }
    };

    return {
        trace: function () { m.log(arguments, "trace"); },
        debug: function () { m.log(arguments, "debug"); },
        info: function () { m.log(arguments, "info"); },
        warn: function () { m.log(arguments, "warn"); },
        error: function () { m.log(arguments, "error"); },
        log: function () { m.log(arguments, undefined); }
    };
}(window.console))

因此,您现在可以在代码中尝试这些并查看结​​果

logger.info("Hello");
logger.trace("Hello");
logger.debug("Hello");
logger.warn("Hello");
logger.error("Hello");
logger.log("Hello");

答案 5 :(得分:1)

作为克里斯回答的一个细微变化,只需将'log'定义为具有空函数的'console'的属性:

if (typeof console === "undefined") {
    console = {
        log: function () {
            return;
        } 
   };
}

答案 6 :(得分:0)

Paul Irish有一个很好的光包装/替代console.log()

http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/

优点:

  • 如果控制台不在(即IE)
  • ,则防止出错
  • 维护日志历史记录,以便您可以查看以后是否添加了控制台(例如firebug lite)
  • Light&简单。
  • 非常快速输入 - log()window.log()

答案 7 :(得分:0)

使用安慰

我可笑的过度设计的控制台:

    如果没有控制台,
  • 可以防止错误
  • 如果您在代码中留下console.log语句
  • ,则会阻止登录生产
  • 支持console.errorconsole.group以及所有其他方法
  • 仍然会让您回溯到日志声明

太棒了。

但实际上,您不应该在代码中留下console个陈述。

看哪,发抖!提出:Consolation.js

答案 8 :(得分:0)

CoffeeScript的:

empty_function = ->
  return
if !window.console?
  window.console = {}
  for fn in ['log', 'info', 'warn', 'debug', 'error']
    if (typeof window.console[fn] isnt 'function')
      window.console[fn] = empty_function

JS:

(function() {
  var empty_function, fn, i, len, ref;

  empty_function = function() {};

  if (window.console == null) {
    window.console = {};
    ref = ['log', 'info', 'warn', 'debug', 'error'];
    for (i = 0, len = ref.length; i < len; i++) {
      fn = ref[i];
      if (typeof window.console[fn] !== 'function') {
        window.console[fn] = empty_function;
      }
    }
  }

}).call(this);

答案 9 :(得分:-1)

我的解决方案有点不同。我为所有console.log调用创建了一个标准快捷方式:在我的情况下,kag(无论我想在控制台中报告什么)。

我测试IE,如果IE我将结果发送到警告框。如果Chrome随后显示在控制台中。这也意味着IE即使在控制台关闭时也会一直工作:

代码:

var iever = getInternetExplorerVersion();
if(iever>-1){
function kag(params){
    alert(params);
}
} else {
var kag = console.log.bind(console, "REPORT: ");
}

function getInternetExplorerVersion() {
var rv = -1;
if (navigator.appName == 'Microsoft Internet Explorer') {
var ua = navigator.userAgent;
var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
if (re.exec(ua) != null){
  rv = parseFloat( RegExp.$1 );
}
}
return rv;
}