【问题标题】:How can I log information about global variables whenever these are created?每当创建全局变量时,如何记录有关这些变量的信息?
【发布时间】:2014-01-18 05:00:54
【问题描述】:

背景

我刚刚了解到,在 DevTools 控制台中调用 keys(window)(或 Object.keys(window))会显示全局范围内的变量(source)。我在 StackOverflow 页面上调用了该代码并得到了以下结果:

变量i 引起了我的注意,因为它似乎错误地位于全局范围内。我尝试查找负责声明i 的代码,但结果很麻烦(代码很多,is 也很多)。

问题

获取控制台警告

已创建全局变量“i” (main.js:342)

可能有用。如何实现该功能?

研究

我认为每当创建新变量时我都需要某种事件。

  • 我们在 JavaScript 中确实有 setters。但是,创建 setter 需要您提供属性名称。因为我想监控所有属性,所以我不能真正使用它。
  • __noSuchMethod__ (MDN) 会很完美,但它只涵盖方法(并且没有 __noSuchProperty__ 方法)。
  • Object.observe (HTML5 Rocks) 没有透露有关创建该属性的代码的任何信息(console.trace() 只给了我观察者函数的名称)。
  • Object.prototype.watch (MDN) - 与 setter 相同,您必须指定属性名称。
  • 无论何时创建新的全局变量,调用Object.preventExtensions(window) (MDN) 都会导致错误并带有良好的堆栈跟踪。此解决方案的问题在于它会干扰脚本执行并可能改变其行为。它也不允许我捕捉错误并正确格式化。

注意事项

  • 我知道 jshint/jslint,但我仍然认为在运行时捕获这些声明可能很有用。
  • 我不太关心 SO 页面上的 i 变量,您可能可以使用 setter 找到声明。我的问题是关于这个问题的一般解决方案。

【问题讨论】:

    标签: javascript debugging global-variables google-chrome-devtools


    【解决方案1】:

    IMO 你有两个不错的选择:

    1. JSHint.
    2. 严格模式。

    当你泄露一个全局变量时,两者都会对你大喊大叫。严格模式可能更适合您的用例。

    【讨论】:

    • 谢谢保罗,我忽略了显而易见的事情。以严格模式抛出的ReferenceError 确实包含我定位泄漏所需的所有信息。我希望一些可以轻松注入页面的东西(例如,找到提到的i 变量的泄漏),但也许我可以以某种方式强制所有脚本使用严格模式 - 我会尝试一下。
    • 明显的时刻。打得好,保罗。
    • 和闭包编译器 + linter。
    【解决方案2】:

    你肯定已经完成了你的作业,你想到了我会想到的所有事情,而且正如你发现的那样,它们都不适合。

    我能想到的唯一方法就是只监视全局对象(此示例使用window 作为全局对象:针对 Node 或其他 JavaScript 容器进行相应修改)。这是一个监控新全局变量和已删除全局变量的示例(如果您不需要监控删除,则可以删除该功能):

    var globals = Object.keys(window);
    var monitorGlobalInterval = 50;
    
    setInterval(function(){
        var globalsNow = Object.keys(window);
        var newGlobals = globalsNow.filter(function(key){
            return globals.indexOf(key)===-1;
        });
        var deletedGlobals = globals.filter(function(key){
            return globalsNow.indexOf(key)===-1;
        });
        newGlobals.forEach(function(key){
            console.log('new global: ' + key);
        });
        deletedGlobals.forEach(function(key){
            console.log('global deleted: ' + key);
        });
        globals = globalsNow;
    }, monitorGlobalInterval);
    

    在此处查看实际操作:http://jsfiddle.net/dRjP9/2/

    【讨论】:

    • 谢谢 Ethan 感谢您的意见!您的代码可以使用Object.observe (polyfill/shim) 进行简化。这个解决方案的问题是我们没有得到任何关于变量声明位置的信息:(
    • 啊,对了,康拉德。我没有对Object.observe 做太多的工作,所以我没有去那里。是的,这对声明位置没有帮助,所以对 OP 来说可能没有多大价值。哦,好吧。
    【解决方案3】:

    你可以试试这个方法来获取你创建的全局变量列表:

    (function(){
      var differences = {},
        ignoreList = (prompt('Ignore filter (comma sep)?', 'jQuery, Backbone, _, $').split(/,\s?/) || []),
        iframe = document.createElement('iframe'),
        count = 0; ignoreList.push('prop');
    
      for (prop in window) {
        differences[prop] = {
          type: typeof window[prop],
          val: window[prop]
        }; count++;
      }
    
      iframe.src = 'about:blank';
      iframe.style.display = 'none';
      document.body.appendChild(iframe);
      iframe = iframe.contentWindow || iframe.contentDocument;
    
      for (prop in differences) {
        if (prop in iframe || ignoreList.indexOf(prop) >= 0) {
          delete differences[prop];
          count--;
        }
      }
    
      console.info('Total globals: %d', count);
      return differences;
    })();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-29
      • 2016-10-25
      • 1970-01-01
      • 1970-01-01
      • 2017-11-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多