console.log.apply 在 IE9 中不起作用

Posted

技术标签:

【中文标题】console.log.apply 在 IE9 中不起作用【英文标题】:console.log.apply not working in IE9 【发布时间】:2011-07-29 04:19:25 【问题描述】:

看起来我重新发明了***,但不知何故,这在 Internet Explorer 9 中不起作用,但在 IE6 中起作用。

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

相关: Apply() question for javascript

F12 调试器告诉我这个“对象”(console.log)不支持方法“应用”。 它甚至不被认为是一种功能吗? 还有其他的建议或想法吗?

【问题讨论】:

【参考方案1】:

IE 的一些宿主对象函数并不是真正的 JavaScript 函数,因此没有 applycall。 (例如alert。)

所以你必须努力做到这一点:

function debug()
  var index;

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

【讨论】:

没错。并非 JS 中所有可调用的东西都必须是 Function 对象。 一开始我也是这么想的。但话又说回来,它之前没有定义。 @line-o:请注意,您在某些地方使用window.console,而在其他地方使用console。现在,在所有其他条件相同的情况下,这些应该会得出相同的结果,但这是我们正在谈论的 IE,如果它与 console.log 玩魔术游戏,我不会完全感到惊讶。 @Tim Down:是的,很像 RegExp 实例的非标准扩展,使它们可以调用。 @TJC,@line-o:console 对象在您第一次启动特定选项卡的开发人员工具之前不存在。【参考方案2】:

好的,这样写就可以了:

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

奇怪的行为......但如果你这样写,'console.log' 会被识别为一个函数。

【讨论】:

查看我对您对我的回答的评论的回复。你的前后矛盾应该没问题,但我敢打赌 IE 正在玩愚蠢的游戏。【参考方案3】:

答案I gave recently 的第二部分也回答了这个问题。我不认为这是一个副本,因此为方便起见,我将其粘贴在这里:

控制台对象不是任何标准的一部分,它是文档对象模型的扩展。与其他 DOM 对象一样,它被视为宿主对象,不需要从 Object 继承,其方法也不需要从 Function 继承,就像原生 ECMAScript 函数和对象一样。这就是 apply 和 call 在这些方法上未定义的原因。在 IE 9 中,大多数 DOM 对象都被改进为继承自原生 ECMAScript 类型。由于开发人员工具被认为是 IE 的扩展(尽管是内置扩展),因此它们显然没有获得与 DOM 的其余部分相同的改进。

对于它的价值,您仍然可以在控制台方法上使用一些 Function.prototype 方法,并带有一点 bind() 魔法:

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

因此,您可以以相同的方式修复 IE 9 的所有 console 方法:

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);

这用调用“主机”函数的本机函数替换了“主机”函数。您可以通过在代码中包含Function.prototype.bindArray.prototype.forEach 的兼容性实现,或者重写上面的sn-p 以结合这些方法使用的技术,让它在Internet Explorer 8 中运行。

另见

console.log typeof is "object" instead of "function" - Microsoft Connect(需要真实帐户)

【讨论】:

+1 当然,该解决方案确实引入了一个新的依赖项:Function#bind,它必须在尚未完全符合 ECMAScript5 规范的实现中提供... 其实是针对IE6的。但它给了我更深入的洞察力并回答了我的问题,这对我帮助很大。所以,非常感谢@Andy 非常感谢@Andy,我需要这个来让我的框架中的调试器在 MSIE 上工作。我已经在源代码中添加了学分,再次感谢! 执行此操作的简短方法是:function debug() Function.prototype.apply.call(console.log, console, arguments); ,这基本上就是 bind-ing 代码所做的。 我希望我能不止一次地支持这个答案。令人惊讶的信息和帮助!谢谢!【参考方案4】:

还有 Paul Irish 的做法。它比上面的一些答案更简单,但是让 log 总是输出一个数组(即使只传入了一个参数):

// 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) );
  
;

【讨论】:

感谢您提出他的好方法。【参考方案5】:

我提出这个问题的原因是我试图对特定模块的 console.log 函数进行“刺激”,因此我可以通过使用 IE 9 的参数来获得更多本地化和有洞察力的调试信息把它弄坏了。

@Andy E 的回答很棒,帮助我了解了很多关于应用的见解。我只是不采用相同的方法来支持 IE9,因此我的解决方案是仅在“现代浏览器”上运行控制台(现代意味着任何浏览器的行为方式都符合我的预期 =)

var C = function() 
  var args = Array.prototype.slice.call(arguments);
  var console = window.console;
  args[0]  = "Module X: "+args[0];
  if( typeof console == 'object' && console.log && console.log.apply )
    console.log.apply(console, args);
  
;

【讨论】:

【参考方案6】:

我遇到了同样的 IE 问题,并为此制定了一个例程。 它不像上述所有实现那样花哨,但它适用于所有现代浏览器。

我使用 Firefox (Firebug)、IE 7、8、9 Chrome 和 Opera 对其进行了测试。 它利用了邪恶的 EVAL,但您只想在开发中进行调试。 之后您将代码替换为debug = function () ;

原来如此。

问候,汉斯

(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);

糟糕,忘记了我的 toType 函数,在这里。

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();

【讨论】:

【参考方案7】:

试试:

function log(type) 
  if (typeof console !== 'undefined' && typeof console.log !== 'undefined' &&
    console[type] && Function.prototype.bind) 
    var log = Function.prototype.bind.call(console[type], console);
    log.apply(console, Array.prototype.slice.call(arguments, 1));
  

log('info', 'test', 'pass');
log('error', 'test', 'fail');

适用于logdebuginfowarnerrorgroupgroupEnd

【讨论】:

以上是关于console.log.apply 在 IE9 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

TypeError:console.log.apply 上的非法调用

为啥 console.log.apply() 会抛出非法调用错误? [复制]

apply 与arguments的用法

多浏览器调试功能

javascript函数声明和函数表达式的区别

跨浏览器Javascript调试器