2010-04-11 67 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); 
相關問題