1

開発中の API に問題があります。それぞれが同じインターフェイスを実装し、静的メソッドを持つクラスの配列が必要です。クラスの配列を循環し、静的メソッドの 1 つの戻り値に基づいて 1 つを選択する別のクラスがありますが、コンパイラは静的メソッドを削除しており、javascript は静的メソッドを呼び出そうとすると TypeError に遭遇します。 . いくつかのフォーラムを検索してみましたが、役立つものが見つかりません。このエラーは、単純ではなく高度なコンパイル モードでのみ発生し、デバッグ モードでの高度なコンパイルでも発生します。

これは、私が関数を呼び出している複雑な方法のために、関数を使用していることをコンパイラが認識していないためだと考えています。

エラーの原因となる、私がやろうとしていることのやや単純化された例をまとめました。

コードについては以下を参照してください。

Racerインターフェイスは、 と の 2 つのクラスによって実装されるRunnerインターフェイスですJogger。インターフェイスには、レーサーが移動できる方法の配列を返す getModesOfTransportation と呼ばれる 1 つの静的メソッドと、同じことを行う getTransportationModes と呼ばれるインスタンス メソッドがあります。このファイルは、キーワードracing.RacerClassで呼び出されたときにレーサー オブジェクトを返す関数である型を (私が思うに) 作成するカスタム型 も定義します。https://developers.google.com/closure/compiler/docs/js-for-compiler#typesnewに基づいてこれを作成しました。型にも静的メソッドがあることを定義する必要があると思いますが、方法がわかりません。このカスタム タイプがエラーの原因でしょうか?

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関数は、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インターフェイスを実装し、2 つの関数の戻り値は['jog']次のとおりです。ファイルの最後で、それ自体をヘルパーに登録します。

ジョガー.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インターフェイスを実装していますが、2 つの関数の戻り値は['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のインスタンスを取得および格納するというパブリック関数があります。関数はレーサーのリストを巡回し、実行できるレーサーを見つけようとしますが、コードがコンパイルされると、それは未定義であると言って失敗します。RacergetRunnergetRunnerracerClass.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.RacerClassただし、 instanceof が である必要がありますRacerClass

編集:

への変更:

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