[英]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.