console.log in Safari doesn’t “apply”. Bad Safari.

It’s not unusual to want to write a cross-browser logging function akin to Firebug’s console.log(). The approach that you would expect to work could quite plausibly be this:

function log() {
   if(console) {
      console.log.apply(this,arguments);
   }
}

We invoke the function with apply here so that implementations that can take multiple arguments receive them.

However, this function breaks Safari (at least it does on version 3.1.2) – causing a helpful message TypeError: type error. At the moment, Safari’s console.log only takes one argument, so a way to fix the above function is as follows:

function log(s) {
   if(console) {
      if(navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1) {
         console.log(s);
      } else {
         console.log.apply(this,arguments);
      }
   }
}

Quite why this is a problem is not clear to me. I did try to submit a bug report to Apple, but arrived at this page instead:

I would appreciate it if someone would try and recreate the problem in Webkit – I’ve at least seen their bug tracker online.

Advertisements

6 Comments

  1. Saq Imtiaz
    Posted November 11, 2008 at 4:27 pm | Permalink

    How about:
    # function log() {
    # if(console) {
    # console.log(arguments);
    # }
    # }

    That should work just as well without needing to use apply, or am I missing something?

  2. Saq Imtiaz
    Posted November 11, 2008 at 4:33 pm | Permalink

    Having given it some more thought, I guess the difference is that without using apply the arguments would be passed as an array which isn’t quite as useful but should still work.

  3. Posted November 11, 2008 at 5:37 pm | Permalink

    I find Safari’s behaviour here quite weird. Normally, you’d expect it to just ignore additional arguments. It’s as if it’s saying “if (arguments.length > 2) throw exception”. An explicit check like that is the only way it could be doing something as annoying as this! That, or it’s some native thing where the error is actually coming from calling a C/C++ function with the wrong number of args.

    I often use this idiom on the fly, so I wanted a simpler bit of code that I can write quickly without having to look up. I think the following will achieve the same effect as above with less finger typing:

    if (console && console.firebug) { console.log.apply(this, arguments); }

  4. Posted November 11, 2008 at 6:32 pm | Permalink

    If you just change:

    console.log.apply(this, arguments)

    to:

    console.log.apply(console, arguments)

    Everything should work.

    And multiple arguments works in the newer WebKit (not Safari 3).

  5. Posted November 12, 2008 at 12:17 pm | Permalink

    Top stuff Tim, thanks.

  6. Posted January 9, 2012 at 1:46 pm | Permalink

    In fact, even Safari 5.1.2 (OSX Lion) still behaves the same. I was glad to find this page as I was unable to see any error in my code đŸ˜‰