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

假设我想包含一些调用console.log的一些合法的生产原因,比如说unit testing工具。 显然,如果浏览器没有console ,或者没有控制台 ,我不希望这个引发过早的exception。

创build一个简单的logfunction将日志logging到控制台的最好方法是什么,或者如果没有控制台存在,就会在没有错误的情况下悄然失败?

上面提到的问题被接受的答案是:

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

这个logfunction可以在IE上正常调用,这里的apply只是为了显示它是可能的? 而且,我从关联的问题中推测,如果IE的控制台在运行时closures,那么这样做会失败,所以即使在控制台打开后, log也不能正常工作。 如果这是错的,有人可以解释它是如何工作的?

这ycombinator文章似乎相关。 他们是否正在谈论与上面链接的问题相同的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来testing它。 这是一个安全包装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

这个日志function可以在IE上正常调用,这里的应用只是为了显示它是可能的?

是的,是的。 这个特殊的例子是直接针对相关问题的“这是一个真正的function”的一部分。

而且,我从关联的问题中推测,如果IE的控制台在运行时closures,那么这样做会失败,所以即使在控制台打开后,日志也不能正常工作。

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

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

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

在上面的例子中,原型服务于一个目的,还是我们只是迂腐…

那么,是的,不。 有些开发人员可能不知不觉地将Function.call改为自定义函数或值。 当然,他们也可以打破Function.prototype.call ,但是这种事故不太可能发生。

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

简单的IE7和以下的垫片,保留其他浏览器的线路编号:

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

对不起,我的post中有一个错误。 不知道我错过了什么。

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

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

我喜欢用:

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

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

尝试使用下面的代码片段(这是我首选的方法,因为它使你独立于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"); 

作为克里斯答案的一个小小的变化,只需用一个空的函数将'log'定义为'console'的一个属性:

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

保罗爱尔兰有一个很好的轻包装/替代console.log()

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

优点:

  • 防止错误,如果控制台不在身边(即IE)
  • 保持日志的历史,所以你可以看过去,如果你的控制台后来添加(如萤火虫)
  • 轻而简单。
  • input很快log()window.log()

使用安慰

我可笑的过度工程控制台:

  • 防止错误,如果没有控制台
  • 如果您在代码中保留console.log语句,将阻止生产日志
  • 支持console.errorconsole.group和所有其他方法
  • 仍然给你回溯到你的日志语句

太奇妙了。

但是,真的,你不应该把console声明留在你的代码中。

看,战栗! 介绍: Consolation.js

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); 

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

我testing的IE浏览器,如果IE我把结果发送到一个警告框。 如果Chrome然后显示在控制台。 这也意味着即使在控制台closures的情况下,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; }