我正在开发的API遇到了问题。我希望有一个类的数组,每个类都实现相同的接口并具有静态方法。我将有另一个类,它将在类的数组中循环,并根据其中一个静态方法的返回值选择一个类,但是编译器正在删除静态方法,并且javascript在尝试调用静态方法时遇到TypeError。我试着搜索了几个论坛,但我找不到任何有用的东西。此错误仅在高级编译模式下发生,并不简单,甚至在调试模式下的高级编译中也会发生。
我想这是因为编译器没有意识到我正在使用这个函数,因为我调用它的方式很复杂。
我已经整理了一个稍微简化的例子,说明我正在尝试做的事情会导致错误。
代码见下文:
Racer接口是由两个类实现的接口:Runner和Jogger。该接口有一个名为getModesOfTransportation的静态方法,它返回racer可以移动的方式的数组,还有一个实例方法,名为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未定义。
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)我希望能够在不将类拆分为只有静态函数的类和只有构造函数的类的情况下工作,因为这会使代码变得混乱。我试过了,但是我做不到。
提前感谢您的任何想法/建议。
发布于 2012-10-05 23:05:30
我认为您可以使用@expose来阻止编译器删除成员。也许我误解了你在问什么。
发布于 2012-10-06 08:27:06
如上所述,“静态”方法是折叠的,@expose通过导出它们来防止这种情况。另一种方法是间接添加以下属性:
function helperAddMyProp(obj, value) {
obj.myProp = value;
}
/** @construcor */
function Foo() {};
helperAddMyProp(Foo, 1);它可能会在稍后被内联,但在属性被折叠之后。这说明了这个问题(在closure compiler.apppot.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);发布于 2012-11-19 10:17:43
如果您将RacerClass更改为@constructor,它将起作用。
/** @typedef function(new:racing.Racer)*/
racing.RacerClass={};// My custom typedef仅对对象属性一致性使用@typedef。它的instanceof是Object。但是你需要racing.RacerClass实例为RacerClass。
编辑:
更改为:
/**
* @constructor
* @implements {racing.Racer}
*/
racing.RacerClass={};// My custom typedefhttps://stackoverflow.com/questions/12748755
复制相似问题