【问题标题】:Adding console.log to every function automatically自动将 console.log 添加到每个函数
【发布时间】:2011-06-29 08:42:51
【问题描述】:

有没有办法通过在某处注册一个全局钩子(即,不修改实际函数本身)或通过其他方式,使任何函数在调用时输出一个 console.log 语句?

【问题讨论】:

  • 很好的问题,我很想知道这是否可能,但我很确定它不是...也许添加一个功能请求,以便将其添加到您的 js 引擎中最喜欢的浏览器? :-)
  • 完美的问题,我需要类似的东西

标签: javascript function logging hook


【解决方案1】:

这是一种使用您选择的函数来扩充全局命名空间中所有函数的方法:

function augment(withFn) {
    var name, fn;
    for (name in window) {
        fn = window[name];
        if (typeof fn === 'function') {
            window[name] = (function(name, fn) {
                var args = arguments;
                return function() {
                    withFn.apply(this, args);
                    return fn.apply(this, arguments);

                }
            })(name, fn);
        }
    }
}

augment(function(name, fn) {
    console.log("calling " + name);
});

一个缺点是调用augment 后创建的任何函数都不会有额外的行为。

【讨论】:

  • 它是否正确处理函数的返回值?
  • @SunnyShah 不,它不会:jsfiddle.net/Shawn/WnJQ5 但这个可以:jsfiddle.net/Shawn/WnJQ5/1 虽然我不确定它是否适用于所有情况......不同之处在于将fn.apply(this, arguments); 更改为return fn.apply(this, arguments);
  • @Shawn @SunnyShah 已修复。只需要在最里面的函数中添加一个return
  • 几乎可以正常工作,但是我在使用这个 jquery:call :if (jQuery.isFunction(lSrc)) 时遇到错误,它说 :TypeError: jQuery.isFunction is not a function
  • 这个解决方案不使用jQuery
【解决方案2】:

您实际上可以将自己的函数附加到 console.log 以获取所有加载的内容。

console.log = function(msg) {
    // Add whatever you want here
    alert(msg); 
}

【讨论】:

  • 正确与否,它不回答问题。一点也不。 (以防有人仍然感到困惑)
【解决方案3】:

这里有一些 Javascript 代替了将 console.log 添加到 Javascript 中的每个函数;在Regex101 上玩它:

$re = "/function (.+)\\(.*\\)\\s*\\{/m"; 
$str = "function example(){}"; 
$subst = "$& console.log(\"$1()\");"; 
$result = preg_replace($re, $subst, $str);

这是一个“快速而肮脏的 hack”,但我发现它对调试很有用。如果你有很多函数,要小心,因为这会添加很多代码。此外,RegEx 很简单,可能不适用于更复杂的函数名称/声明。

【讨论】:

    【解决方案4】:

    如果您想要更有针对性的日志记录,以下代码将记录特定对象的函数调用。您甚至可以修改对象原型,以便所有新实例也可以记录。我使用了 Object.getOwnPropertyNames 而不是 for...in,因此它适用于没有可枚举方法的 ECMAScript 6 类。

    function inject(obj, beforeFn) {
        for (let propName of Object.getOwnPropertyNames(obj)) {
            let prop = obj[propName];
            if (Object.prototype.toString.call(prop) === '[object Function]') {
                obj[propName] = (function(fnName) {
                    return function() {
                        beforeFn.call(this, fnName, arguments);
                        return prop.apply(this, arguments);
                    }
                })(propName);
            }
        }
    }
    
    function logFnCall(name, args) {
        let s = name + '(';
        for (let i = 0; i < args.length; i++) {
            if (i > 0)
                s += ', ';
            s += String(args[i]);
        }
        s += ')';
        console.log(s);
    }
    
    inject(Foo.prototype, logFnCall);
    

    【讨论】:

      【解决方案5】:

      记录函数调用的代理方法

      在 JS 中有一种使用Proxy 的新方法来实现此功能。 假设我们希望在调用特定类的函数时拥有console.log

      class TestClass {
        a() {
          this.aa = 1;
        }
        b() {
          this.bb = 1;
        }
      }
      
      const foo = new TestClass()
      foo.a() // nothing get logged
      

      我们可以用覆盖这个类的每个属性的代理来替换我们的类实例化。所以:

      class TestClass {
        a() {
          this.aa = 1;
        }
        b() {
          this.bb = 1;
        }
      }
      
      
      const logger = className => {
        return new Proxy(new className(), {
          get: function(target, name, receiver) {
            if (!target.hasOwnProperty(name)) {
              if (typeof target[name] === "function") {
                console.log(
                  "Calling Method : ",
                  name,
                  "|| on : ",
                  target.constructor.name
                );
              }
              return new Proxy(target[name], this);
            }
            return Reflect.get(target, name, receiver);
          }
        });
      };
      
      
      
      const instance = logger(TestClass)
      
      instance.a() // output: "Calling Method : a || on : TestClass"
      

      check that this actually works in Codepen


      请记住,使用 Proxy 可以为您提供比仅记录控制台名称更多的功能。

      此方法也适用于 Node.js

      【讨论】:

      【解决方案6】:

      对我来说,这看起来是最优雅的解决方案:

      (function() {
          var call = Function.prototype.call;
          Function.prototype.call = function() {
              console.log(this, arguments); // Here you can do whatever actions you want
              return call.apply(this, arguments);
          };
      }());
      

      【讨论】:

      • RangeError: 超出最大调用堆栈大小。节点js的任何替代品
      猜你喜欢
      • 1970-01-01
      • 2014-09-18
      • 1970-01-01
      • 1970-01-01
      • 2013-04-13
      • 2019-09-29
      • 1970-01-01
      • 2022-11-04
      • 2020-12-13
      相关资源
      最近更新 更多