【问题标题】:Intercept calls to console.log in Chrome在 Chrome 中拦截对 console.log 的调用
【发布时间】:2012-03-02 06:04:17
【问题描述】:

我有一个无法更改的脚本,它会产生很多console.log 调用。如果调用包含某些字符串,我想添加另一层并做出响应。这适用于 Firefox,但在第 4 行的 Chrome 中会引发“Illegal invocation”错误:

var oldConsole = {};
oldConsole.log = console.log;
console.log = function (arg) {
    oldConsole.log('MY CONSOLE!!');
    oldConsole.log(arg);
}

任何想法如何解决这个问题?我也尝试克隆控制台...

【问题讨论】:

    标签: javascript debugging console


    【解决方案1】:

    您需要在console 的上下文中调用console.log for chrome:

    (function () {
      var log = console.log;
      console.log = function () {
        log.call(this, 'My Console!!!');
        log.apply(this, Array.prototype.slice.call(arguments));
      };
    }());
    

    现代语言功能可以显着简化这个 sn-p:

    {
      const log = console.log.bind(console)
      console.log = (...args) => {
        log('My Console!!!')
        log(...args)
      }
    }
    

    【讨论】:

    • 不错...一直在寻找这样的东西。这可以用来装饰javascript中的任何函数吗?
    • @Shane,这是拦截函数调用的基本模式,但除非绝对必要,否则我建议不要使用它。最好直接修改函数,或者使用OOP概念。
    • 构建一个包含大量运行时组件组装的框架,这将是一个方便的工具,可用于外部驱动的方法来调试组件或使用插件修改现有组件等。是否会影响性能对于这种方法?只是好奇会有什么缺点。我不会修改内部函数,只会修改框架组件方法。
    • 您调用的每个函数都会对“性能造成影响”,但偶尔触发的异步 JavaScript 不应严重停滞。
    • 看起来函数链明显更快。刚做了一个测试。 jsperf.com/wrapped-function
    【解决方案2】:

    我知道这是一篇旧帖子,但它仍然很有用,因为其他解决方案与旧浏览器不兼容。

    您可以像这样重新定义控制台(以及所有浏览器)的每个功能的行为:

    // define a new console
    var console = (function(oldCons){
        return {
            log: function(text){
                oldCons.log(text);
                // Your code
            },
            info: function (text) {
                oldCons.info(text);
                // Your code
            },
            warn: function (text) {
                oldCons.warn(text);
                // Your code
            },
            error: function (text) {
                oldCons.error(text);
                // Your code
            }
        };
    }(window.console));
    
    //Then redefine the old console
    window.console = console;
    

    【讨论】:

    【解决方案3】:

    您也可以使用相同的逻辑,但从控制台对象中调用它,因此上下文是相同的。

    if(window.console){
      console.yo = console.log;
      console.log = function(str){
        console.yo('MY CONSOLE!!');
        console.yo(str);
      }
    }
    

    【讨论】:

      【解决方案4】:

      使用 ES6 新的扩展运算符你可以这样写

      (function () {
        var log = console.log;
        console.log = function () {
          log.call(this, 'My Console!!!', ...arguments);
        };
      }());
      

      【讨论】:

        【解决方案5】:

        可以很简单:

        console.log = (m) => terminal.innerHTML = JSON.stringify(m)
        #terminal {background: black; color:chartreuse}
        $ > <span id="terminal"></span>
        <hr>        
        <button onclick="console.log('Hello world!!')">3V3L</button>
        <button onclick="console.log(document)">3V3L</button>
        <button onclick="console.log(Math.PI)">3V3L</button>

        【讨论】:

          【解决方案6】:

          由于我(还)无法评论 @ludovic-feltz 的答案,因此他的答案已更正以允许在控制台中进行字符串插值:

          // define a new console
          var console = (function(oldCons){
              return {
                  log: function(...text){
                      oldCons.log(...text);
                      // Your code
                  },
                  info: function (...text) {
                      oldCons.info(...text);
                      // Your code
                  },
                  warn: function (...text) {
                      oldCons.warn(...text);
                      // Your code
                  },
                  error: function (...text) {
                      oldCons.error(...text);
                      // Your code
                  }
              };
          }(window.console));
          
          //Then redefine the old console
          window.console = console;
          

          【讨论】:

            【解决方案7】:

            要完全拦截控制台,我们可以覆盖所有方法:

            const bindConsole=function(onMessage){
                Object.keys(console)
                .filter(type=>typeof(console[type])==='function')// *1
                .forEach(type=>{
                    let _old=console[type];
                    console[type] = function (...args) {
                        _old.apply(console,args);
                        onMessage(type,args);// *2
                    };
                });
            };
            

            对于旧浏览器:

            var bindOldConsole=function(onMessage){
                for(var k in console){// *1
                    if(typeof(console[k])=='function')(function(type){
                        var _old=console[type];
                        console[type] = function () {
                            _old.apply(console,arguments);
                            onMessage(type,arguments);
                        };
                    })(k);
                }
            };
            

            • *1 看起来 console 只有方法,但最好确定一下。

            • *2 您可以通过将此行替换为:

              来阻止从 onMessage 对控制台的循环调用:

            if(!isCyclic())onMessage(type,args);

            // es6. Not sure concerning old browsers :(
            const isCyclic=function (){
                let erst=(new Error()).stack.split('\n');
                return erst.includes(erst[1],2);
            };
            

            【讨论】:

              猜你喜欢
              • 2014-01-07
              • 2018-10-29
              • 2014-10-21
              • 1970-01-01
              • 2016-09-24
              • 2011-07-07
              • 1970-01-01
              • 2012-11-04
              • 2014-11-05
              相关资源
              最近更新 更多