0

我正在使用Google Closure Compile使用 ADVANCED_OPTIMIZATIONS 编译以下代码 :

(function() {
  /** @const */
  var DEBUG = false;

  var Namespace = {};
  window['Namespace'] = Namespace;

  (function() {
     /**
      * @constructor
      */
    function Test(tpl) {
      Helper.debug('Test');
    }

    Namespace['Test'] = Test;

  })();

  var Helper = 
    (function(){
       /**
        * @constructor
        */
      function Helper(){
        this.debug = function(arg){
          if(DEBUG){
            console.log(arg);
          }
        }
      };

      return new Helper;
    })();

})();

我的目的是让编译器在什么时候剥离所有 Helper.debug 消息DEBUG == false,并在什么时候将调试函数重命名为一个短名称DEBUG == true。我希望编译器能得到这样的东西:

DEBUG == false

var a={};window.Namespace=a;a.Test=function(){};

DEBUG == true

var a={};window.Namespace=a;a.Test=function(){console.log("Test")};

我最终得到了这个:

DEBUG == false

 var a={};window.Namespace=a;a.Test=function(){b.debug("Test")};var b=new function(){this.debug=function(){}};

DEBUG == true

var a={};window.Namespace=a;a.Test=function(){b.debug("Test")};var b=new function(){this.debug=function(c){console.log(c)}};

在这两种情况下,debug函数都没有重命名。我认为它应该是,因为它没有被导出,也不能从Namespace. 它仅从Namespace.Test()构造函数中调用。如果我不从那里调用它,Closure 会剥离调试功能(因为它没有在任何地方使用),但我希望能够通过命名空间中的函数调用它,并且仍然可以对其进行重命名。

我已经尝试了上述代码的各种版本。使用prototype.debug on Helper,将Helper 构造函数移动到与命名空间相同的范围等。只要调试函数附加到我的Helper 对象,我就找不到从编译器获得所需输出的方法。

如果我不使用 Helper 对象,而只是声明debug为一个函数,我会得到我想要的输出,但这只是一个示例,我确实有许多附加到 Helper 对象的函数,我希望它们全部被重命名为短名称。给出我想要的输出的示例代码:

(function() {
  /** @const */
  var DEBUG = false;

  var Namespace = {};
  window['Namespace'] = Namespace;

  (function() {
     /**
      * @constructor
      */
    function Test(tpl) {
      debug('Test');
    }

    Namespace['Test'] = Test;

  })();

  function debug(arg){
    if(DEBUG){
      console.log(arg);
    }
  }

})();
4

1 回答 1

1

我尝试了您的代码,发现名称debug没有转换,但其他名称会。用 alert 替换了 console.log,因为我没有 console.log 的 externs 文件。这是您修改后的代码(仅将调试重命名为“某事”并将 console.log 重命名为警报):

(function() {
  /** @const */
  var DEBUG = false;

  var Namespace = {};
  window['Namespace'] = Namespace;

  (function() {
     /**
      * @constructor
      */
    function Test(tpl) {
      Helper.something('Test');
    }

    Namespace['Test'] = Test;

  })();

  var Helper = 
    (function(){
       /**
        * @constructor
        */
      function Helper(){
        this.something = function(arg){
          if(DEBUG){
            alert(arg);
          }
        }
      };

      return new Helper;
    })();

})();

编译您的代码现在或多或少具有预期的输出(不使用构造函数):

java -jar compiler.jar --js helper.js --js_output_file out.js --compilation_level=ADVANCED_OPTIMIZATIONS --formatting=PRETTY_PRINT --warning_level=VERBOSE

(function() {
  var a = {};
  window.Namespace = a;
  (function() {
    a.Test = function() {
    }
  })()
})();

将 DEBUG 设置为 true 会给我:

(function() {
  var a = {};
  window.Namespace = a;
  (function() {
    a.Test = function() {
      b.a()
    }
  })();
  var b = function() {
    return new function() {
      this.a = function() {
        alert("Test")
      }
    }
  }()
})();

请注意,引用的属性不会被重命名。所以使用this['something'] = function(arg){andHelper['something']('Test');会导致某些东西不被重命名。我的猜测是你已经知道了,因为你正在使用 window['namespase']['Test']

[更新]

闭包编译器不会重命名外部定义的方法。例如,“document”是在编译器使用的 extern 中定义的(如果不是,那么每次使用 document 都会导致错误)。因此,如果要重命名Helper.debugHelper.getElementById仍然不会重命名它(getElementById 在编译器默认使用的 externs 文件中定义)。这是 Oreilly.Closure.The.Definitive.Guide.Sep.2010 第 391 页的来源:

var mystery = function(obj) {
alert(obj.max());
};

因为神秘没有任何类型信息,obj 可以是内置的 Math 对象或 example.NumSet。因为 Math 可能作为参数提供给神秘,所以编译器无法重命名 max() 方法。出于这个原因,编译器采用保守的方法来重命名变量,如果变量也出现在外部变量中,则从不重命名它。这是 Compiler 默认不包含额外的 externs 文件(例如 contrib/externs 中的那些)的主要原因之一:向 externs 池添加更多名称可能会不必要地减少 Compiler 完成的变量重命名量。

即使您提供类型信息,编译器也不会在没有一些额外标志的情况下重命名 --use_types_for_optimization。您的代码仍然不会重命名调试,但这可能是因为您需要一个 typedef。将 debug 重命名为 myDebug 会导致函数被重命名。

为什么 Closure Compiler 不重命名具有某些名称的对象?

于 2013-06-04T00:50:29.917 回答