RSS
 

Internet Explorer 9′s problematic console object

04 Apr

I sent out a quick tweet the other day after answering this question on Stack Overflow. Apparently, Internet Explorer 9 had caused the asker some confusion by not giving the console object permanent residency as part of the DOM – you have to open the developer tools for any tab you want the object to be made available to first. As an aside, the asker also wondered why when he tried to use console.log.apply, he got an error. After some quick investigations, it appeared obvious that the console object being injected into the window by the developer tools hadn’t received an update since Internet Explorer 8 and so the methods it contains aren’t instances of Function like all the most other DOM methods. The first thing that popped into my head was to try Function.prototype.bind.apply and see if it worked, although I wasn’t optimistic.

var log = Function.prototype.bind.call(console.log, console);
log.apply(console, ["this", "is", "a", "test"]);

To my surprise, it worked great. I posted it as my answer and sent out the tweet to let the world know the crisis was over. Then, today a similar question was posted, again asking why console.log.apply doesn’t work. I had a little more time, so decided to rework the solution to apply to all the console methods that IE supports. Whilst writing the function, I discovered that IE still reports console methods as objects when using the typeof operator:

typeof console.log;
//-> "object"

This actually violates the ECMAScript 5th edition’s rules for the typeof operator, which specifies “function” should be returned for both native and host objects that implement [[Call]]. I headed over to Microsoft Connect to see if they were still accepting bug reports, but decided to search first and found that kangax had beaten me to it (he reported it pre beta and got a generic “we’re investigating” response). Instead, I 1-upped his bug report and added my workaround, which I’ll also post here in a slightly more concise form:

if (Function.prototype.bind && console && typeof console.log == "object") {
  [ 
    "log","info","warn","error","assert","dir","clear","profile","profileEnd" 
  ].forEach(function (method) {
    console[method] = this.call(console[method], console);
  }, Function.prototype.bind);
}

Now if we take another look at these methods, we should get (more or less) the same result in each browser:

typeof console.log;
//-> "function"
    
Object.prototype.toString.call(console.log);
//-> "[object Function]"

console.log.apply(console, ["this", "is", "a", "test"]);
//-> "thisisatest"

The usefulness of Function.prototype.bind here got me thinking — if we can make native copies of host objects, perhaps we can make native copies of ActiveX objects and methods too? nope.

Update

You can achieve the same result with IE 8′s console too, using a compatibility implementation of bind, but you must bind to Function.prototype.call, rather than console.log:

var log = Function.prototype.call.bind(console.log, console);
typeof log;
//-> "function"
 

Tags: , , , , ,

Leave a Reply

 

 
  1. Paul Irish

    April 5th, 2011 at 2:18 am

    This post was magnificent.

    Very sexy workaround. :)

     
  2. CharliePops

    April 7th, 2011 at 7:58 pm

    in the update… I guess you meant ‘Function.prototype.bind.call’ instead ‘Function.prototype.call.bind’

     
    • Andy

      April 7th, 2011 at 8:31 pm

      Nope, I meant what I said :-) In IE 8, the compatibility implementation of bind tries to execute call as a member of the function passed in, so it will fail for console.log because it has no such method. Binding console.log to Function.prototype.call instead works as expected.

       
  3. Craig Patik

    April 8th, 2011 at 2:23 pm

    The IE8 method does not work (“Object doesn’t support this property or method”). Neither `Function.prototype.call.bind` nor `Function.prototype.bind` are defined.

    This works well in IE8:

    if (!Function.prototype.bind && console && typeof console.log == ‘object’) {
    var log = function () {
    Function.prototype.call.call(console.log, console, Array.prototype.slice.call(arguments));
    }
    }

    thanks to @kangax.

    It doesn’t take care of log.apply(), but then you can do log(‘my message’) and it shows up in the Developer Tools console. Plus you can easily combine it with Paul’s great console.log wrapper.

     
    • Andy

      April 9th, 2011 at 8:31 am

      Craig, I think you meant Function.prototype.call.apply in your/kanax’s solution. It’s also a decent approach and apply should work with it. I mention at the bottom that the IE 8 solution requires the compatibility implementations of bind and forEach, which you can find on their respective pages at the MDC JavaScript documentation.

       
  4. Complete cross-browser console.log() » console.blog()

    April 12th, 2011 at 11:32 pm

    [...] to tell IE9 to use its own console and to consider console.log() to be a function. Many thanks to Andy for this [...]

     
  5. Alberto

    May 6th, 2011 at 7:04 am

    Is this code compatible with prototypejs?

     
    • Andy

      May 6th, 2011 at 10:48 am

      There shouldn’t be any reason why it wouldn’t be.

       
  6. Jay Querido

    August 8th, 2011 at 8:01 pm

    This is awesome!

    BTW, Andy, I’d love to be able to +1 this or tweet this or something. Perhaps think of adding the sexybookmarks plugin or something?

     
    • Andy

      August 24th, 2011 at 4:29 pm

      Jay,

      Done, thanks for the tip :-)

       
  7. Heretic-Monkey.com » Blog Archive » console.log for everyone, including IE8, IE9, Firefox, Chrome and possibly Safari! - Monkey trouble

    August 14th, 2011 at 2:10 am

    [...] Searching about with the BinGooHoo got me to this question on the excellent StackOverflow, which led me to the following article: Internet Explorer 9?s problematic console object. [...]

     
  8. Pablo Palomar

    September 1st, 2011 at 8:42 am

    Perfect, very usseful

     
  9. David Harkness

    June 20th, 2013 at 5:27 pm

    In the main IE9 solution, are bind and call reversed in the forEach()?

     
    • Andy

      June 21st, 2013 at 1:14 pm

      That’s right. IE 9 has Function.prototype.bind built-in, but compatibility implementations usually throw if you call it on something that isn’t a function (which was the original problem here). So, you can bind to Function.prototype.call instead to work around that issue.

      Basically, either way will work in IE 9/10, but binding to call is necessary for IE 8 or lower.

       
  10. Vladimir Varankin

    September 9th, 2013 at 12:16 pm

    `if (Function.prototype.bind && console && typeof console.log == “object”)`

    You will probably catch “ReferenceError: console is not defined” error here in old browsers like IE7. So `typeof console !== ‘undefined’` should be used.