google closure compiler's advanced optimization isn't optimizing some variables
I'm running into an issue with the Google Closure Javascript compiler with advanced optimization. As the documentation suggests, to preserve exported Javascript I do something like this:
var myClass = function() {
this["myFunc"] = this.myFunc;
this["myFunc2"] = this.myFunc2;
};
window["myClass"] = myClass;
myClass.prototype = {
myFunc: function() { alert("myFunc"); },
myFunc2: function() { alert("myFunc2"); }
};
The issue is that sometimes, for whatever reason, myFunc
and myFunc2
开发者_C百科don't get shortened, and I see code like this in the final output:
x.myFunc=x.myFunc;x.myFunc2=x.myFunc2;
This is obviously less than ideal.
How can I prevent this from happening?
Further experimentation has shown that there are certain keywords, e.g. 'get' that don't get compiled.
var myClass = function() {
this["get"] = this.get;
this["myFunc2"] = this.myFunc2;
};
window["myClass"] = myClass;
myClass.prototype = {
get: function() { alert("myFunc"); },
myFunc2: function() { alert("myFunc2"); }
};
Compiles into
function a() {
this.get = this.get;
this.myFunc2 = this.a
}
window.myClass = a;
a.prototype = {get:function() {
alert("myFunc")
}, a:function() {
alert("myFunc2")
}};
I still don't know what's causing it though.
I cannot duplicate your problem. If I go to http://closure-compiler.appspot.com/home and compile the following:
// ==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"); }
};
Then I get the following result:
function a(){this.myFunc=this.a;this.myFunc2=this.b}window.myClass=a;a.prototype={a:function(){alert("myFunc")},b:function(){alert("myFunc2")}};
The properties are renamed, as expected.
As for your second example, it has to do with a Closure Compiler concept known as externs. An extern is a symbol that will be predefined in the environment in which the JavaScript will run, such as window
or document
in the case of Web programming. Because such names are fixed in the environment, the Compiler cannot mangle these names.
If you look at the DEFAULT_EXTERNS_NAMES
list in CommandLineRunner.java, you will see a list of files from the externs folder. The contents of these files define the externs that the Compiler knows about (you can also add your own externs). Both webgl.js
and w3c_indexeddb.js
define types with a property named get
(WebGLContextAttributes
and IDBObjectStore
, respectively). By default, the Compiler does not know the type of this
in myClass
, so as far as it knows, this
could refer to an instance of either WebGLContextAttributes
or IDBObjectStore
, in which case it would not be safe to rename get
.
By using a combination of type annotations (such as @constructor
) and Compiler options such as ambiguateProperties
and disambiguateProperties
, the Compiler can determine that this
will always refer to a new instance of myClass
and rename all of its references to get
consistently. You can read more about these Compiler optimizations in Chapter 14 of Closure: The Definitive Guide.
From the example here, it looks like you need to explicitly export prototype methods outside of the constructor:
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;
This seems to work as advertised, though it seems like an odd optimization to me (all the repeated "prototype" references add a lot of bytes):
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;
The reason is that, with ADVANCED_OPTIMIZATIONS, the GCC treats myObject["a"] differently from myObject.a. Try the following:
var myObject = {};
myObject.attr1 = 3;
myObject["attr2"] = 4;
window["myObject"] = myObject;
It will compile to this, with ADVANCED_OPTIMIZATIONS:
window.myObject={a:3,attr2:4};
I think you'll see what you need to do now.
精彩评论