[英]How to have an array of classes with static methods when using the closure compiler?
我正在开发的API遇到问题。 我想要一个类数组,每个类实现相同的接口并具有静态方法。 我将有另一个类,该类将遍历类的数组并根据静态方法之一的返回值选择一个,但是编译器正在删除静态方法,并且javascript在尝试调用静态方法时遇到TypeError 。 我尝试搜索多个论坛,但找不到任何有用的信息。 此错误仅在高级编译模式下发生,而不是简单,甚至在调试模式下的高级编译下发生。
我在想这是因为编译器没有意识到我正在使用该函数,因为调用它的方式很复杂。
我整理了一个尝试做的会导致错误的简化示例。
参见下面的代码:
Racer
接口是由两个类实现的接口: Runner
和Jogger
。 该接口具有一个称为getModesOfTransportation的静态方法,该方法返回赛车程序可以移动的方式的数组,而一个名为getTransportationModes的实例方法执行相同的操作。 该文件还定义了一个自定义类型racing.RacerClass
,该类型(我认为)是一种类型,该类型是一个函数,当使用new
关键字调用该函数时会返回racer对象。 我是根据https://developers.google.com/closure/compiler/docs/js-for-compiler#types形成的。 我认为我应该定义该类型也具有静态方法,但是我不知道怎么做。 此自定义类型可能是错误的根源吗?
racer.js:
goog.provide('racing.Racer');
/** @typedef function(new:racing.Racer)*/
racing.RacerClass={};// My custom typedef
/**
* Interface for racers.
* @interface
*/
racing.Racer=function(){};
/**
* Gets the ways this racer can move.
* @return {Array.<string>} The ways this racer can move.
*/
racing.Racer.getModesOfTransportation=function(){}
/**
* Gets the ways this racer can move.
* @return {Array.<string>} The ways this racer can move.
*/
racing.Racer.prototype.getTransportationModes=function(){}
Helper
类存储Racer构造函数的列表。 registerRacer
函数接受Racer
的构造函数并将其添加到列表中。 传递的构造函数上还将具有静态的getModesOfTransportation
函数。 getRacers
函数返回已注册的赛车手的列表。
helper.js:
goog.provide('racing.Helper');
/**
* A collection of functions to help with finding racers.
*/
racing.Helper={};
/**
* An array of racers.
* @type {Array.<racing.RacerClass>}
* @private
*/
racing.Helper.racers_=[]
/**
* Adds the given racer to the list.
* @param {racing.RacerClass} racer A racer to add to the list of racers.
*/
racing.Helper.registerRacer=
function(racer){
racing.Helper.racers_.push(racer);
}
/**
* Gets an array of registered racers.
* @return Array.<racing.RacerClass> A list of all registered racers.
*/
racing.Helper.getRacers=
function(){
return racing.Helper.racers_;
}
Jogger
类实现了Racer
接口,两个函数的返回值为['jog']
。在文件末尾,它向帮助程序注册了自己。
jogger.js:
goog.provide('racing.Jogger');
goog.require('racing.Racer');
goog.require('racing.Helper');
/**
* This racer can jog.
* @constructor
*/
racing.Jogger=function(){
console.log('Jogger is going');
};
/**
* Gets the ways this racer can move.
* @static
* @return {Array.<string>} The ways this racer can move.
*/
racing.Jogger.getModesOfTransportation=
function(){
return ['jog'];//I can jog
}
/**
* Gets the ways this racer can move.
* @return {Array.<string>} The ways this racer can move.
*/
racing.Jogger.prototype.getTransportationModes=
function(){
return ['jog'];//I can jog
}
//Register this racer
racing.Helper.registerRacer(racing.Jogger);
Runner
类也实现了Racer
接口,但是两个函数的返回值为['run']
。在文件末尾,它向帮助程序注册了自己。
Runner.js:
goog.provide('racing.Runner');
goog.require('racing.Racer');
goog.require('racing.Helper');
/**
* This racer can run.
* @constructor
*/
racing.Runner=
function(){
console.log('Runner is going');
};
/**
* Gets the ways this racer can move.
* @static
* @return {Array.<string>} The ways this racer can move.
*/
racing.Runner.getModesOfTransportation=
function(){
return ['run'];//I can run
}
/**
* Gets the ways this racer can move.
* @return {Array.<string>} The ways this racer can move.
*/
racing.Runner.prototype.getTransportationModes=
function(){
return ['run'];//I can run
}
//Register this racer
racing.Helper.registerRacer(racing.Runner);
Organizer
类具有一个称为startRace
的公共函数,该函数获取并存储Racer
的实例,该实例可以通过调用受保护的getRunner
函数来运行。 getRunner
函数在赛车程序列表中循环,并尝试找到可以运行的赛车程序,但是,一旦编译了代码, racerClass.getModesOfTransportation()
失败, getModesOfTransportation
未定义getModesOfTransportation
。
Organizer.js:
goog.provide('racing.Organizer');
goog.require('racing.Helper');
goog.require('goog.array');
/**
* Class that helps with starting a race.
* @constructor
*/
racing.Organizer=function(){}
/**
* A racer that can run.
* @protected
* @returns {racing.Racer}
*/
racing.Organizer.prototype.runner=null;
/**
* Get a racer that can run.
* @protected
* @returns {racing.Racer}
*/
racing.Organizer.prototype.getRunner=
function(){
//Cycle through the racers until we find one that can run.
goog.array.findIndex(racing.Helper.getRacers(),
function(racerClass){
if(goog.array.contains(racerClass.getModesOfTransportation(),'run')){
this.runner=new racerClass();
return true;
}
else return false;
},this
);
}
/**
* Starts a race.
*/
racing.Organizer.prototype.startRace=
function(){
this.runner=this.getRunner();
}
最终文件仅包含编译器的所有类。
api.js:
//Include the racers
goog.require('racing.Runner');
goog.require('racing.Jogger');
//Include the organizer and export its properties
goog.require('racing.Organizer')
goog.exportSymbol('racing.Organizer', racing.Organizer);
goog.exportProperty(racing.Organizer.prototype, 'startRace', racing.Organizer.prototype.startRace);
运行new racing.Organizer().startRace();
在调试模式下的已编译代码上,会产生以下错误,并且当我查看已编译的代码时, getModesOfTransportation
函数不再存在:
Uncaught TypeError: Object function () {
console.log("Runner is going")
} has no method '$getModesOfTransportation$'
$$racing$Organizer$$$$$startRace$$
(anonymous function)
我希望能够在不将类拆分为仅具有静态函数的类和仅包含构造函数的类的情况下使其工作,因为这会使代码令人困惑。 我试图弄清楚,但我做不到。
预先感谢您的任何想法/建议。
我认为您也许可以使用@expose
阻止编译器删除成员。 也许我误会了您的要求。
如上所述,“静态”方法已折叠,并且@expose通过导出它们来防止这种情况。 替代方法是间接添加属性:
function helperAddMyProp(obj, value) {
obj.myProp = value;
}
/** @construcor */
function Foo() {};
helperAddMyProp(Foo, 1);
稍后可能会内联,但是在属性折叠后。 这表明了问题所在(在closure-compiler.appspot.com上):
// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// @output_file_name default.js
// @formatting pretty_print
// @debug true
// ==/ClosureCompiler==
function Foo(name) {
alert('Hello, ' + name);
}
Foo.prop = 2;
Foo("me");
alert(Foo.prop);
这是解决方案:
// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// @output_file_name default.js
// @formatting pretty_print
// @debug true
// ==/ClosureCompiler==
function addProp(obj, value) {
obj.prop = value;
}
function Foo(name) {
alert('Hello, ' + name);
}
addProp(Foo,2);
Foo("me");
alert(Foo.prop);
如果将RacerClass
更改为@constructor
,它将起作用。
/** @typedef function(new:racing.Racer)*/
racing.RacerClass={};// My custom typedef
仅将@typedef
用于对象属性的一致性。 它的instanceof
是Object
。 但是您需要racing.RacerClass
instanceof成为RacerClass
。
编辑:
改成:
/**
* @constructor
* @implements {racing.Racer}
*/
racing.RacerClass={};// My custom typedef
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.