2010-04-11 114 views
7

我希望尽可能缩短日志语句,同时防止控制台在不存在时被访问;我想出了以下解决方案:将console.log分配给另一个对象(Webkit问题)

var _ = {}; 
if (console) { 
    _.log = console.debug; 
} else { 
    _.log = function() { } 
} 

对我来说,这似乎是很优雅,它工作在Firefox 3.6中大(包括保留的行号,使console.debugconsole.log更有用)。但它在Safari 4中不起作用。[更新:或在Chrome中。所以,这个问题似乎是萤火虫和WebKit的控制台之间的差异。如果我按照上面

console.debug('A') 
_.log('B'); 

的第一条语句工作在这两个浏览器很好,但第二生成:在“类型错误类型错误”苹果浏览器。这只是Firebug和Safari Web Developer Tools如何实现控制台的区别?如果是这样,这是非常讨厌 Apple的 Webkit的一部分。将控制台函数绑定到原型然后实例化,而不是直接将其绑定到对象,这没有帮助。

我当然可以从拨给_.log的匿名函数中调用console.debug,但是我会丢失行数。任何其他想法?

+0

它的WebKit的功能,而不是一个错误;-) https://bugs.webkit.org/show_bug.cgi?id=20141 – 2010-10-14 18:12:43

+0

相关:http://stackoverflow.com/questions/14146316/why-does-scope-reduction-in-safari-break-existing-code – MvG 2013-04-19 13:57:34

回答

8

首先,如果console确实是未定义的(因为它在诸如IE等浏览器中),则会出现错误。您应该将其作为全局对象的属性进行检查,即浏览器中的window。在使用它之前测试一个功能通常也是一个好主意,所以我为debug方法添加了一个测试。

可能的console.debug Safari中的实现依赖于它的this其事console的参考,这将不会是,如果你把它用_.logthis反而是_参考)的情况下的价值。做完一个简单的测试,这似乎是这种情况和以下修复问题:

var _ = {}; 
if (typeof window.console != "undefined" 
     && typeof window.console.debug == "function") { 
    _.log = function() { 
     window.console.debug.apply(window.console, arguments); 
    } 
} else { 
    _.log = function() { } 
} 
+3

对,这是传统的方法,但它有一个严重的缺陷:它失去了路线数字。如果您在应用程序的任何位置调用_.log(),则控制台会将该输出报告为从_.log()函数内生成,而不是原始源。因此,使用console.debug()而不是console.log()的好处会丢失。 – 2010-04-13 00:37:22

+2

在这种情况下,如果坚持使用没有任何别名或包装的'console',并且仅使用存根方法定义它(如果它不存在的话)是不是更容易?例如:if(typeof window.console!=“undefined”){window.console = {debug:function(){}}}'等等 – 2010-04-13 09:14:42

+0

我认为你是对的,蒂姆(尽管你的意思是typeof窗口.console ==“undefined”而不是'!=',对不对?)。我也许应该放弃追求简洁,转而根据需要分配一个虚拟控制台。 – 2010-04-23 18:54:10

0

我一直在寻找一个解决方案,这一点我自己(我这是怎么找到你的问题)。

正如Tim指出的那样,在这种情况下,webkit浏览器(Safari,Chrome)依靠thisconsole。然而,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); 
相关问题