[英]Module pattern with Closure Compiler and ADVANCED_OPTIMIZATIONS
I am aware that similar questions have been asked before, but methodology changes quickly so I'm seeking to understand current best practices. 我知道之前已经提出了类似的问题,但方法很快就会发生变化,因此我正在寻求了解当前的最佳实践。 (In fact, as recently as 2 days ago, Chad Killingsworth added a comment to an accepted answer from three years ago that @expose
annotation is now deprecated.) (事实上,就在2天前,Chad Killingsworth对三年前接受的答案添加了评论,即@expose
注释现已弃用。)
I'm using the module pattern . 我正在使用模块模式 。 Working JSFIDDLE of the below code: 使用以下代码的JSFIDDLE :
/** @const */
var MATHCALCS = (function () {
'use strict';
var MY = {};
/**
* @constructor
* @param {!Object} obj
* @expose
*/
MY.ModuleStruct = function (obj) {
/** @expose */
this.color = (obj.color !== undefined) ? obj.color : null;
/** @expose */
this.size = (obj.size !== undefined) ? obj.size : null;
};
/**
* @expose
*/
MY.ModuleStruct.prototype.clone = function () {
return new MY.ModuleStruct({
"color": this.color,
"size": this.size
});
};
MY.moduleProperty = 1;
/**
* @type {function(!Array<number>)}
* @expose
*/
MY.moduleMethod = function (a) {
var i, x = 0;
for (i = 0; i < a.length; i += 1) {
x = x + a[i];
}
return x;
};
return MY;
}());
window["MATHCALCS"] = MATHCALCS;*
Currently, using @expose
annotation, above can be minified with Closure in advance mode and the following calls work ( minified example ): 目前,使用@expose
注释,可以使用Closure in advance模式缩小上面的内容,并且以下调用可以工作( 缩小示例 ):
// call a public method
alert(MATHCALCS.moduleMethod([1, 2, 3]));
// allocate a new structure
var ms = new MATHCALCS.ModuleStruct({
"color": "red",
"size": "small"
});
alert(ms.color + '\t' + ms.size);
// clone a second instance
var ms2 = ms.clone();
alert(ms2.color + '\t' + ms2.size);
alert(ms !== ms2); // cloned objs are not equal
// and directly update the properties of the object
ms2.color = "white";
ms2.size = "large";
alert(ms2.color + '\t' + ms2.size);
If possible, without changing away from the module pattern, I would like to update code (approx 10,000 lines) to use @export
annotation. 如果可能的话,在不改变模块模式的情况下,我想更新代码(大约10,000行)以使用@export
注释。 However, when I replace @expose
with @export
Closure raises this error: 然而,当我更换@expose
与@export
关闭引发此错误:
ERROR - @export only applies to symbols/properties defined in the global scope. 错误 - @export仅适用于全局范围中定义的符号/属性。
Q: Is it possible, and if so, how should the above code be annotated to work with ADVANCED_OPTIMIZATIONS? 问:是否可能,如果可行,上述代码应如何注释以使用ADVANCED_OPTIMIZATIONS?
I am aware that I can possibly use this type of notation: 我知道我可以使用这种表示法:
MY["ModuleStruct"] = MY.ModuleStruct;
MY["ModuleStruct"]["prototype"]["clone"] = MY.ModuleStruct.prototype.clone;
but exporting object properties this way will become tedious. 但以这种方式导出对象属性将变得乏味。 Further JSLint complains about weird assignments so I would rather use JSDocs annotation. 进一步的JSLint抱怨奇怪的任务,所以我宁愿使用JSDocs注释。
Until the issue raised by @ChadKillingsworth is resolved, here's a solution which will enable you to use @export
with only minor modifications to your code: 在@ChadKillingsworth提出的问题得到解决之前,这里有一个解决方案,只需对代码进行少量修改即可使用@export
:
/** @const */
var MATHCALCS = {};
goog.scope(function () {
'use strict';
var MY = MATHCALCS;
/**
* @constructor
* @param {!Object} obj
* @export
*/
MY.ModuleStruct = function (obj) {
this.color = (obj.color !== undefined) ? obj.color : null;
this.size = (obj.size !== undefined) ? obj.size : null;
};
/**
* @export
*/
MY.ModuleStruct.prototype.clone = function () {
return new MY.ModuleStruct({
"color": this.color,
"size": this.size
});
};
MY.moduleProperty = 1;
/**
* @type {function(!Array<number>)}
* @export
*/
MY.moduleMethod = function (a) {
var i, x = 0;
for (i = 0; i < a.length; i += 1) {
x = x + a[i];
}
return x;
};
});
The changes are: 变化是:
@expose
tags to @export
. 将@expose
标记更改为@export
。 MATHCALCS
object outside the module wrapper function, and make the MY
alias point to it. 在模块包装函数外部创建一个空的MATHCALCS
对象,并使MY
别名指向它。 goog.scope()
. 不是立即执行模块包装函数(IIFE),而是将其传递给goog.scope()
。 This enables aliasing within scope functions, allowing the compiler to work out that the exported symbols are being defined on the global MATHCALCS
object. 这样可以在范围函数中启用别名,从而允许编译器确定在全局MATHCALCS
对象上定义导出的符号。 This prevents the compiler from raising the error (" @export
only applies to symbols/properties defined in the global scope"). 这可以防止编译器引发错误(“ @export
仅适用于在全局范围中定义的符号/属性”)。 @export
tags on this.color
and this.size
this.color
和this.size
上的@export
标记 return MY;
window["MATHCALCS"] = MATHCALCS;
When compiled with this command: 使用此命令编译时:
java -jar compiler.jar \
--js closure/goog/base.js \
--js mathcalcs.js \
--js_output_file mathcalcs.min.js \
--compilation_level ADVANCED_OPTIMIZATIONS \
--generate_exports \
--formatting PRETTY_PRINT \
--output_wrapper '(function() {%output%}).call(window);'
you'll get: 你会得到:
(function() {var f = this;
function g(a, d) {
var b = a.split("."), c = f;
b[0] in c || !c.execScript || c.execScript("var " + b[0]);
for (var e;b.length && (e = b.shift());) {
b.length || void 0 === d ? c[e] ? c = c[e] : c = c[e] = {} : c[e] = d;
}
}
;function h(a) {
this.color = void 0 !== a.color ? a.color : null;
this.size = void 0 !== a.size ? a.size : null;
}
g("MATHCALCS.ModuleStruct", h);
h.prototype.clone = function() {
return new h({color:this.color, size:this.size});
};
h.prototype.clone = h.prototype.clone;
g("MATHCALCS.moduleMethod", function(a) {
var d, b = 0;
for (d = 0;d < a.length;d += 1) {
b += a[d];
}
return b;
});
}).call(window);
The g()
function is the compiled version of goog.exportSymbol()
– see the @export
docs for more details. g()
函数是goog.exportSymbol()
的编译版本 - 有关更多详细信息,请参阅@export
文档 。
Note: if you want to run the code uncompiled, you'll need to load the Closure Library, or define goog.scope()
yourself: 注意:如果要运行未编译的代码,则需要加载Closure库,或者自己定义goog.scope()
:
var goog = {};
goog.scope = function(fn) {
fn();
};
Here's a fork of your JSFiddle with all these changes. 这是你的JSFiddle的一个分支,包含所有这些变化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.