我怎样才能重写这个,以便Closure Compile重命名我的函数?

时间:2013-05-31 17:09:15

标签: javascript google-closure-compiler

我使用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;
    })();

})();

我的意图是编译器在DEBUG == false时删除所有Helper.debug消息,并在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剥离调试函数(因为它没有在任何地方使用),但我希望能够通过Namespace中的函数调用它,并且仍然可以重命名。

我已尝试过上述代码的各种版本。在Helper上使用prototype.debug,将Helper构造函数移动到与Namespace等相同的范围。只要调试函数附加到我的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);
    }
  }

})();

1 个答案:

答案 0 :(得分:1)

我尝试了您的代码,发现名称debug未转换,但其他名称将被转换。将alert.log替换为alert,因为我没有console.log的externs文件。这是您修改过的代码(仅将调试重命名为'something',将console.log重命名为alert):

(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){Helper['something']('Test');会导致某些内容无法重命名。我的猜测是你已经知道了,因为你正在使用window ['namespase'] ['Test']

<强> [更新]

Closure编译器不会重命名externs中定义的方法。例如,“document”在编译器使用的extern中定义(如果不是每次使用document都会导致错误)。因此,如果您要将Helper.debug重命名为Helper.getElementById,它仍然不会重命名它(getElementById在编译器默认使用的externs文件中定义)。以下是Oreilly.Closure.TheDefinitive.Guide.Sep.2010第391页的来源:

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

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

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

Why does Closure Compiler not rename objects with certain names?