1

我正在开发的 API 有问题。我想要一个类数组,每个类都实现相同的接口并具有静态方法。我将有另一个类循环遍历类数组并根据其中一个静态方法的返回值选择一个,但是编译器正在删除静态方法,并且 javascript 在尝试调用静态方法时遇到 TypeError . 我试过搜索几个论坛,但我找不到任何有用的东西。这个错误只发生在高级编译模式下,不简单,甚至在调试模式下的高级编译中也会出现。

我认为这是因为编译器没有意识到我正在使用该函数,因为我调用它的方式很复杂。

我已经整理了一个稍微简化的示例,说明我正在尝试执行的操作会导致错误。

请参阅下面的代码:

Racer接口是由两个类实现的接口:RunnerJogger。该接口有一个名为 getModesOfTransportation 的静态方法,它返回一组赛车手可以移动的方式,以及一个名为 getTransportationModes 的实例方法,它执行相同的操作。该文件还定义了一个自定义类型,racing.RacerClass,(我认为)创建一个类型,该类型是一个函数,当使用new关键字调用时会返回一个 Racer 对象。我基于https://developers.google.com/closure/compiler/docs/js-for-compiler#types形成了这个。我认为我应该定义该类型也有一个静态方法,但我不知道如何。这种自定义类型可能是错误的罪魁祸首吗?

赛车手.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函数接受 a 的构造函数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']在文件的末尾,向helper注册自己。

慢跑者.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']在文件的末尾,它向助手注册了自己。

亚军.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是未定义的。

组织者.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)

我希望能够使其工作,而不必将类拆分为仅具有静态函数的类和仅具有构造函数的类,因为这会使代码混乱。我试图弄清楚这一点,但我做不到。

提前感谢您的任何想法/建议。

4

3 回答 3

3

我认为您可能可以@expose用来阻止编译器删除成员。或者我可能误解了你在问什么。

于 2012-10-05T15:05:30.027 回答
3

如上所述,“静态”方法被折叠,@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);
于 2012-10-06T00:27:05.937 回答
0

如果您更改RacerClass@constructor,它将起作用。

/** @typedef function(new:racing.Racer)*/
racing.RacerClass={};// My custom typedef

仅用于@typedef对象属性一致性。它instanceofObject。但是你需要racing.RacerClassinstanceof 是RacerClass.

编辑:

改成:

/** 
* @constructor 
* @implements {racing.Racer} 
*/
racing.RacerClass={};// My custom typedef
于 2012-11-19T02:17:43.007 回答