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"
Paul Irish
April 5th, 2011 at 2:18 am
This post was magnificent.
Very sexy workaround.
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
bindtries to executecallas a member of the function passed in, so it will fail forconsole.logbecause it has no such method. Bindingconsole.logtoFunction.prototype.callinstead works as expected.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.applyin your/kanax’s solution. It’s also a decent approach andapplyshould work with it. I mention at the bottom that the IE 8 solution requires the compatibility implementations ofbindandforEach, which you can find on their respective pages at the MDC JavaScript documentation.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 [...]
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.
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
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. [...]
Pablo Palomar
September 1st, 2011 at 8:42 am
Perfect, very usseful