How to safely wrap `console.log`?

随声附和 提交于 2019-12-02 17:24:44

Can this log function be called normally on IE, and the use of apply here is just to show it's possible?

Yes, and yes. That particular example was aimed squarely at the "is it a real function" part of the linked question.

And, I assume from the linked question that this will fail if IE's console is closed when it runs, so log won't work even after the console opens, correct?

Correct. As explained in my answer on that question, the console object is not exposed until the first time the developer tools are opened for a particular tab. Most developers use a console shim, in which case the Function#bind approach becomes a little obsolete because you may as well use the Function#apply.apply method.

What is the purpose of converting arguments to an array in this case?

There isn't one, it's redundant. Unless it's a custom log implementation, in which case the developer may have a reason to convert an arguments object to an array.

And does prototype serve a purpose in the above examples, or are we just being pedantic...

Well, yes and no. Some developer may have unwittingly changed Function.call to a custom function or value. Of course, they could break Function.prototype.call too, but this is far less likely to happen by accident.

The problem with wrappers is that they will obfuscate file name and line number of the source of the log message.

Simple IE7 and below shim that preserves Line Numbering for other browsers:

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

Sorry, there was a bug in my post. Don't know how I missed it.

The PROPER way to create a global console object, if it does not exist:

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

I like to use:

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

It works in all browsers and is easy to understand.

Try using the code snippet below... (this is my preferred approach because it makes you independent of 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))

So you may now try these in your code and see the result

logger.info("Hello");
logger.trace("Hello");
logger.debug("Hello");
logger.warn("Hello");
logger.error("Hello");
logger.log("Hello");

As a slight variation on Chris' answer, simply define 'log' as a property of 'console' with an empty function:

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

Paul Irish has a nice light wrapper/replacement for console.log().

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

Advantages:

  • Prevent errors if a console isn’t around (i.e. IE)
  • Maintains a history of logs, so you can look in the past if your console is added afterwards (e.g. firebug lite)
  • Light & simple.
  • Very quick to type -- log() or window.log().

Use Consolation

My ridiculously overengineered console:

  • prevents errors if there's no console
  • prevents logging in production if you left console.log statements in your code
  • supports console.error, console.group, and all such other methods
  • still gives you backtraces to your log statements

It's amazing.

But really, you just shouldn't leave console statements lying around in your code.

Behold and tremble! Presenting: 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);

My solution is a little different. I create a standard shortcut for all console.log calls: In my case kag(whatever I want to report in the console).

I test for IE, if IE I send the results to an alert box. If Chrome then displays in the console. This also means IE will always work even in console is closed:

Code:

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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!