我想让我的日志记录语句尽可能短,同时防止在不存在时访问控制台;我提出了以下解决方案:
var _ = {};
if (console) {
_.log = console.debug;
} else {
_.log = function() { }
}
对我而言,这似乎相当优雅,并且在Firefox 3.6中运行良好(包括保留使console.debug
比console.log
更有用的行号)。但它在Safari 4中不起作用。[更新:或在Chrome中。所以问题似乎是Firebug和Webkit控制台之间的区别。]如果我按照
console.debug('A')
_.log('B');
第一个语句在两个浏览器中都能正常工作,但第二个语句在Safari中生成“TypeError:Type Error”。这只是Firebug和Safari Web开发人员工具如何实现控制台之间的区别吗?如果是这样,那么 Apple的 Webkit就非常烦人了。将控制台功能绑定到原型然后实例化,而不是直接将其绑定到对象,这没有用。
我当然可以从分配给console.debug
的匿名函数中调用_.log
,但之后我会丢失我的行号。还有其他想法吗?
答案 0 :(得分:8)
首先,如果console
确实未定义(因为它在IE等浏览器中),则会出现错误。您应该将其检查为全局对象的属性,即浏览器中的window
。一般来说,在使用它之前测试一个功能也是个好主意,所以我为debug
方法添加了一个测试。
Safari中console.debug
的实施可能依赖于this
作为console
的引用的价值,如果您使用_.log
调用它,情况就不会如此(this
将改为_
)的引用。完成快速测试后,情况确实如此,以下问题解决了这个问题:
var _ = {};
if (typeof window.console != "undefined"
&& typeof window.console.debug == "function") {
_.log = function() {
window.console.debug.apply(window.console, arguments);
}
} else {
_.log = function() { }
}
答案 1 :(得分:0)
我一直在寻找解决方案(这就是我发现你的问题的方法)。
Tim指出,在这种情况下,webkit浏览器(Safari,Chrome)依赖于this
console
。但是,Firefox没有。所以在FF中你可以重新分配函数并保留行号(否则所有日志看起来都像是在日志函数中发起的,这不是很有用)。检查您的浏览器的最佳方法是执行此操作并检查结果。以下是如何检查它(在Coffeescript中):
# Check to see if reassigning of functions work
f = console.log
assignSupported = true
try
f('Initializing logging...')
catch e
assignSupported = false
稍后,当您执行这些功能时,请检查assignSupported并采取相应措施:
levels =
ERROR: 1
WARN: 2
LOG: 3
INFO: 4
DEBUG: 6
log.setLevel = (newLevel) ->
for label, level of levels
if level > newLevel # Skip low levels
continue
name = label.toLowerCase()
f = -> # Fallback - empty function. In Js: var f = function () {}
if console?[name]
if assignSupported
f = console[name] # Wee, we'll have line numbers.
else
# Webkit need the this of console.log (namely, console)
# preserved, so we use a wrapper.
#
# Calling console[name] within the returned wrapper
# makes [name] a subject of the closure, meaning
# that it's the last value in the iteration -
# we need to preserve it.
f = ((n) ->
return (-> console[n].apply(console, arguments)))(name)
log[name] = f
log.setLevel levels.DEBUG
行:
f = ((n) ->
return (-> console[n].apply(console, arguments)))(name)
可能看起来有点奇怪。这是因为name
是循环变量并且是词法绑定的,这意味着将使用执行时的值,这将始终是最后的level
。它编译为这个javascript(如果它更容易阅读):
f = (function(n) {
return (function() {
return console[n].apply(console, arguments);
});
})(name);