【问题标题】:google closure compiler's advanced optimization isn't optimizing some variables谷歌闭包编译器的高级优化没有优化一些变量
【发布时间】:2011-07-04 20:05:34
【问题描述】:

我在使用高级优化的 Google Closure Javascript 编译器时遇到了问题。正如文档所建议的那样,为了保留导出的 Javascript,我会执行以下操作:

var myClass = function() {
   this["myFunc"] = this.myFunc;
   this["myFunc2"] = this.myFunc2;
};
window["myClass"] = myClass;

myClass.prototype = {
    myFunc: function() { alert("myFunc"); },
    myFunc2: function() { alert("myFunc2"); }
};

问题是,有时,无论出于何种原因,myFunc 和 myFunc2 都没有缩短,我在最终输出中看到这样的代码:

x.myFunc=x.myFunc;x.myFunc2=x.myFunc2;

这显然不太理想。

如何防止这种情况发生?


进一步的实验表明存在某些关键字,例如'get' 不会被编译。

var myClass = function() {
   this["get"] = this.get;
   this["myFunc2"] = this.myFunc2;
};
window["myClass"] = myClass;

myClass.prototype = {
    get: function() { alert("myFunc"); },
    myFunc2: function() { alert("myFunc2"); }
};

编译成

function a() {
  this.get = this.get;
  this.myFunc2 = this.a
}
window.myClass = a;
a.prototype = {get:function() {
  alert("myFunc")
}, a:function() {
  alert("myFunc2")
}};

我还是不知道是什么原因造成的。

【问题讨论】:

    标签: javascript google-closure-compiler


    【解决方案1】:

    我无法复制您的问题。如果我去http://closure-compiler.appspot.com/home 并编译以下内容:

    // ==ClosureCompiler==
    // @compilation_level ADVANCED_OPTIMIZATIONS
    // @output_file_name default.js
    // ==/ClosureCompiler==
    
    var myClass = function() {
      this["myFunc"] = this.myFunc;
      this["myFunc2"] = this.myFunc2;
    };
    window["myClass"] = myClass;
    
    myClass.prototype = {
      myFunc: function() { alert("myFunc"); },
      myFunc2: function() { alert("myFunc2"); }
    };
    

    然后我得到以下结果:

    function a(){this.myFunc=this.a;this.myFunc2=this.b}window.myClass=a;a.prototype={a:function(){alert("myFunc")},b:function(){alert("myFunc2")}};
    

    按预期重命名属性。

    至于您的第二个示例,它与称为 externs 的闭包编译器概念有关。 extern 是在 JavaScript 运行的环境中预定义的符号,例如在 Web 编程的情况下为 window 或 document。因为这些名称在环境中是固定的,所以编译器无法破坏这些名称。

    如果您查看CommandLineRunner.java 中的DEFAULT_EXTERNS_NAMES 列表,您将看到externs 文件夹中的文件列表。这些文件的内容定义了编译器知道的外部变量(您也可以添加自己的外部变量)。 webgl.js 和 w3c_indexeddb.js 都使用名为 get 的属性定义类型(分别为 WebGLContextAttributes 和 IDBObjectStore)。默认情况下,编译器不知道this 在myClass 中的类型,所以据它所知,this 可以引用WebGLContextAttributes 或IDBObjectStore 的实例,在这种情况下它不会请放心重命名get。

    通过使用类型注释(例如@constructor)和编译器选项(例如ambiguateProperties 和disambiguateProperties)的组合,编译器可以确定this 将始终引用myClass 和一致地将其所有引用重命名为get。您可以在 Closure: The Definitive Guide 的第 14 章中阅读有关这些编译器优化的更多信息。

    【讨论】:

    • 我应该特别使用哪些注释?
    • 如何通过命令行界面设置歧义/消除歧义?
    • 您需要使用包含类型信息的注解:@constructor、@extends、@param 和@return。
    • 不幸的是,您无法从命令行界面设置歧义/消除歧义。您的选择是 (1) 使用 plovr(我推荐,但我有偏见!),或 (2) 以编程方式使用编译器并编写 Java 代码以启用这些通道。
    【解决方案2】:

    从example here 看来,您需要在构造函数之外显式导出原型方法:

    var myClass = function() {};
    myClass.prototype = {
        myFunc: function() { alert("myFunc"); },
        myFunc2: function() { alert("myFunc2"); }
    };
    
    window["myClass"] = myClass;
    myClass.prototype["myFunc"] = myClass.prototype.myFunc;
    myClass.prototype["myFunc2"] = myClass.prototype.myFunc2;
    

    这似乎像宣传的那样有效,尽管对我来说这似乎是一个奇怪的优化(所有重复的“原型”引用都增加了很多字节):

    function a(){}a.prototype={a:function(){alert("myFunc")},
    b:function(){alert("myFunc2")}};
    window.myClass=a;
    a.prototype.myFunc=a.prototype.a;
    a.prototype.myFunc2=a.prototype.b;
    

    【讨论】:

      【解决方案3】:

      原因是,对于 ADVANCED_OPTIMIZATIONS,GCC 将 myObject["a"] 与 myObject.a 区别对待。请尝试以下操作:

      var myObject = {};
      myObject.attr1 = 3;
      myObject["attr2"] = 4;
      window["myObject"] = myObject;
      

      它将使用 ADVANCED_OPTIMIZATIONS 编译为此:

      window.myObject={a:3,attr2:4};
      

      我想你会明白你现在需要做什么。

      【讨论】:

      • 没有。我明白这一点,这就是我做this["xyz"] = this.xyz 的原因。这类似于window["myObject"] = myObject,除非我遗漏了什么。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-06
      • 1970-01-01
      相关资源
      最近更新 更多