console.log.apply not working in IE9

20,960

Solution 1

The second part of an answer I gave recently answers this question too. I don't consider this a duplicate of that one so, for convenience, I'll paste it here:

The console object is not part of any standard and is an extension to the Document Object Model. Like other DOM objects, it is considered a host object and is not required to inherit from Object, nor its methods from Function, like native ECMAScript functions and objects do. This is the reason apply and call are undefined on those methods. In IE 9, most DOM objects were improved to inherit from native ECMAScript types. As the developer tools are considered an extension to IE (albeit, a built-in extension), they clearly didn't receive the same improvements as the rest of the DOM.

For what it's worth, you can still use some Function.prototype methods on console methods with a little bind() magic:

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

So you could fix up all the console methods for IE 9 in the same manner:

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

This replaces the "host" functions with native functions that call the "host" functions. You can get it working in Internet Explorer 8 by including the compatibility implementations for Function.prototype.bind and Array.prototype.forEach in your code, or rewriting the above snippet to incorporate the techniques used by those methods.

See also

Solution 2

There is also Paul Irish's way of doing it. It is simpler than some of the answers above, but makes log always output an array (even if only one argument was passed in):

// usage: log('inside coolFunc',this,arguments);
// http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
window.log = function(){
  log.history = log.history || [];   // store logs to an array for reference
  log.history.push(arguments);
  if(this.console){
    console.log( Array.prototype.slice.call(arguments) );
  }
};

Solution 3

Several of IE's host object functions aren't really JavaScript functions and so don't have apply or call. (alert, for example.)

So you'll have to do it the hard way:

function debug()
  var index;

  if(!window.console) { 
    window.console = { log: function() { /* do something */ } };
  }
  for (index = 0; index < arguments.length; ++index) {
      console.log(arguments[index]);
  }
}

Solution 4

I came across the same IE trouble and made a routine for it. It is not as fancy as all the above implementations, but it works in ALL modern browsers.

I tested it with Firefox (Firebug), IE 7,8,9 Chrome and Opera. It makes use of the evil EVAL, but you will only want to debug in development. Afterwards you will replace the code with debug = function () {};

So here it is.

Regards, Hans

(function(ns) {
  var msgs = [];

  // IE compatiblity
  function argtoarr (args,from) {
    var a = [];
    for (var i = from || 0; i<args.length; i++) a.push(args[i]);
    return a;    
  }

  function log(arg) {
    var params = "", format = "", type , output,
        types = {
            "number" : "%d",
            "object" : "{%o}",
            "array" : "[%o]"
        };
    for (var i=0; i<arg.length; i++) {
        params += (params ? "," : "")+"arg["+i+"]";
        type = types[toType(arg[i])] || "%s";
        if (type === "%d" && parseFloat(arg[i]) == parseInt(arg[i], 10)) type = "%f";
        format += (format ? "," : "")+type;
    }
    // opera does not support string format, so leave it out
    output = "console.log("+(window.opera ? "" : "'%f',".replace("%f",format))+"%p);".replace("%p",params);
    eval(output);
  }

  ns.debug = function () {
    msgs.push(argtoarr(arguments));
    if (console !== undefined) while (msgs.length>0) log(msgs.shift());
  }

})(window);

Oops forgot my toType function, here it is.

function toType(obj) {
    if (obj === undefined) return "undefined";
    if (obj === null) return "null";
    var m = obj.constructor;
    if (!m) return "window";
    m = m.toString().match(/(?:function|\[object)\s*([a-z|A-Z|0-9|_|@]*)/);
    return m[1].toLowerCase();
}
Share:
20,960

Related videos on Youtube

line-o
Author by

line-o

Developer with a heart for design, graphics, quality, testing and usability freelance developer and consultant former senior dev at white label eCommerce former senior dev at commerce plus

Updated on November 28, 2020

Comments

  • line-o
    line-o over 3 years

    Looks like I've re-invented the wheel, but somehow this isn't working in Internet Explorer 9, but does in IE6.

    function debug()
      if(!window.console) { 
        window.console = { log: function() { /* do something */ } };
      }
      console.log.apply(console, arguments);
    }
    

    Related: Apply() question for javascript

    F12 Debugger tells me that this "object" (console.log) does not support method 'apply'. Is it not even recognized as a function? Any other pointers or ideas?

  • Tim Down
    Tim Down about 13 years
    Exactly. Not everything in JS that is callable is required to be a Function object.
  • line-o
    line-o about 13 years
    I thought that too, at first. But then again, it wasn't defined before.
  • T.J. Crowder
    T.J. Crowder about 13 years
    @line-o: Note that you're using window.console in some places, and console in others. Now, all else being equal, those should come to the same thing, but this is IE we're talking about and I wouldn't be at all surprised if it plays magic games with console.log.
  • T.J. Crowder
    T.J. Crowder about 13 years
    See my reply to your comment on my answer. You're being inconsistent in a way that should be fine, but I bet IE is playing silly games.
  • Andy E
    Andy E about 13 years
    @Tim Down: true, much like the non-standard extension to RegExp instances that makes them callable. @TJC, @line-o: the console object doesn't exist until the first time you launch the developer tools for a particular tab.
  • T.J. Crowder
    T.J. Crowder about 13 years
    +1 The solution does, of course, introduce a new dependency: Function#bind, which one would have to supply on implementations that aren't quite up to ECMAScript5 spec yet...
  • Andy E
    Andy E about 13 years
    @TJC: yeah, that's right - I should have mentioned that this code should be targeted towards IE 9 only :-)
  • line-o
    line-o about 13 years
    Actually, it was targeted at IE6. But it helped me a lot by giving me deeper insight and answered my question. So, thank you very much @Andy
  • Christian
    Christian almost 13 years
    Thanks a bunch @Andy, I needed this to get the debugger in my framework working on MSIE. I've put credits in the source, thanks again!
  • Sophie Alpert
    Sophie Alpert over 12 years
    The short way to do this is: function debug() { Function.prototype.apply.call(console.log, console, arguments); } which is essentially what this bind-ing code does.
  • Andy E
    Andy E over 12 years
    @Ben: "short way"? Character count puts bind() a tad shorter than apply() :-) However, the main difference is that your method is natively compatible with IE 8, whereas the compatibility implementation of bind() would be required for the method outlined in my answer.
  • Sophie Alpert
    Sophie Alpert over 12 years
    Yes, that's what I meant. :) Also when going through the implementation of bind, it wasn't as clear to me what it was doing and how it was avoiding console.log.apply; just wanted to post a comment in case anyone else was confused similarly in the future.
  • line-o
    line-o over 11 years
    Thanks, for bringing up his nice approach.
  • KOGI
    KOGI about 11 years
    I wish I could upvote this answer more than once. Amazingly informative and helpful! Thanks!
  • David Harkness
    David Harkness almost 11 years
    You have bind and call reversed compared to your blog post. I think you mean to bind to call rather than calling bind, i.e., the blog post is reversed. Unfortunately, I don't have IE9 here to test. :(
  • Andy E
    Andy E almost 11 years
    @DavidHarkness: both work in IE9, but the solution I posted here also works for IE8 and lower with a compatibility implementation of bind() :-) See the update at the bottom of my blog post.
  • jiyinyiyong
    jiyinyiyong over 10 years
    But in Chrome console.log == "object" always returns false, I'm quite wondering if that is correct?
  • Andy E
    Andy E over 5 years
    @OuuGiii done. For future reference, you can edit any answer yourself, or suggest edits that are reviewed by other users if your rep is not high enough.

Related