2010-04-11 14 views
7

Quería mantener mis instrucciones de registro lo más breves posible, evitando que se acceda a la consola cuando no existe; Se me ocurrió la siguiente solución:Asignación de console.log a otro objeto (problema de Webkit)

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

Para mí, esto parece bastante elegante, y funciona muy bien en Firefox 3.6 (incluyendo la preservación de los números de línea que hacen console.debug más útil que console.log). Pero no funciona en Safari 4. [Actualización: O en Chrome. Así que la cuestión parece haber una diferencia entre Firebug y la consola Webkit] Si sigo lo anterior con

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

la primera declaración funciona bien en ambos navegadores, pero el segundo genera una "TypeError: Tipo de error" en Safari. ¿Es esto solo una diferencia entre la implementación de la consola por parte de Firebug y Safari Web Developer Tools? Si es así, es MUY molesto en Apple's parte del Webkit. La vinculación de la función de la consola a un prototipo y la creación de instancias, en lugar de vincularlo directamente al objeto, no ayuda.

Podría, por supuesto, simplemente llamar al console.debug desde una función anónima asignada al _.log, pero luego perdería mis números de línea. ¿Alguna otra idea?

+0

Es una característica de webkit, no un error ;-) https://bugs.webkit.org/show_bug.cgi?id=20141 –

+0

Relacionado: http://stackoverflow.com/questions/14146316/why-does-scope-reduction-in-safari-break-existing-code – MvG

Respuesta

8

En primer lugar, si console es de hecho indefinido (como en navegadores como IE), obtendrá un error. Debería comprobarlo en su lugar como una propiedad del objeto global, que es window en los navegadores. También es una buena idea en general probar una característica antes de usarla, así que agregué una prueba para el método debug.

Posiblemente la aplicación de console.debug en Safari se basa en su valor de this siendo una referencia para console, que no será el caso si usted lo llama utilizando _.log (this en su lugar ser una referencia a _). Después de haber hecho una prueba rápida, esto no parece ser el caso y las siguientes revisiones del problema:

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

Correcto, ese es el enfoque convencional, pero tiene un defecto grave: pierde la línea números. Si llama _.log() desde cualquier lugar de la aplicación, la consola informará que la salida se generó desde la función _.log(), no desde la fuente original. Así que se pierde la ventaja de usar console.debug() en lugar de console.log(). –

+2

En ese caso, ¿no sería más fácil limitarse a usar 'console' sin ningún alias o envoltorio, y simplemente definirlo con métodos stub si no existe? Por ejemplo: 'if (typeof window.console! =" Undefined ") {window.console = {debug: function() {}}}' etc. –

+0

Creo que tienes razón, Tim (aunque te refieres a 'typeof window .console == "undefined" 'en vez de'! = ', ¿no?). Quizás debería abandonar mi búsqueda de la brevedad a favor de simplemente asignar una consola ficticia según sea necesario. –

0

He estado buscando una solución a este mismo (así es como me encontré a su pregunta).

Como señaló Tim, los navegadores web (Safari, Chrome) se basan en this siendo console en este caso. Firefox, sin embargo, no. Por lo tanto, en FF puede reasignar la función y conservar los números de línea (de lo contrario, todos los registros parecen originarios de la función de registro, que no es muy útil). La mejor manera de verificar qué navegador es usted es hacerlo y verificar el resultado. Aquí es cómo comprobar que (en CoffeeScript):

# Check to see if reassigning of functions work 
f = console.log 
assignSupported = true 
try 
    f('Initializing logging...') 
catch e 
    assignSupported = false 

Más tarde, cuando usted hace las funciones de verificación assignSupported y actuar en consecuencia:

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 

Las líneas:

f = ((n) -> 
    return (-> console[n].apply(console, arguments)))(name) 

puede tener un aspecto un poco raro. Esto se debe a que name es la variable de bucle y está ligado léxicamente, lo que significa que se usará el valor en el momento de la ejecución, que siempre será el último level.Que recopile con este javascript (en caso de que sea más fácil de leer):

f = (function(n) { 
    return (function() { 
    return console[n].apply(console, arguments); 
    }); 
})(name); 
Cuestiones relacionadas