4

Google Chrome 拡張機能を作成し、クロージャー スコープ内でローカル変数の参照を取得しようとしています。

// The script model of the target website
// I can't change any code of these
function Player(playerName){
    this.name = playerName;
    this.score = 0;
}

function Match(playerRed,playerBlue){
    var player_red = new Player(playerRed);
    var player_blue = new Player(playerBlue);
}

var tennis = new Match("Mike","John")

だから私がコンテンツスクリプトでやろうとしているのはMatch 、変数を取得するためだけにplayer_redプロトタイプに関数を挿入することですplayer_blue:

function Match(playerRed,playerBlue){
    var player_red = new Player(playerRed);
    var player_blue = new Player(playerBlue);

    //hoping to add this into Match.prototype
    this.showMatchInfo = function(){
            alert(player_red.name + " vs " + player_blue.name);
    }
}

しかし、 とが で定義されていないためplayer_red、これは機能しません。player_bluethis

検索でこの質問を見つけました。解決策は、「コンストラクターを新しいコンストラクターでラップしてから、プロトタイプを等しく設定する」ことです。残念ながら、ウェブサイトの元のスクリプトにアクセスできないため、これはうまくいきません。おそらく次の理由が考えられます。

  • new を作成してもmyMatch、 newは元のインスタンスからand変数をmyMatch継承しません。player_redplayer_blueMatch
  • 考えられる回避策はありますか? ありがとう。
4

1 に答える 1

2

「部分解決」に関する注意事項:

以下に掲載されたコードスニペットは、「十分に提供できる場合と提供しない場合があるいくつかの代替案」のみを示していることに注意してください。これは、コンストラクター内で値 (Player オブジェクト) をキャプチャせず、内部に入る値のみをラップするためです。

「完全なソリューション」では、Player コンストラクターをラップし、プロパティまたはその他のメカニズムを使用して、さまざまな入力値に対して作成されたオブジェクトを「記憶」することもできます。または、オブジェクトの作成順序を記憶することもできます。これを使用して Match をラップし、Match コンストラクターの実行後に作成された Player を共有ストアから抽出できますが、これらの詳細は演習として残します。Player ラッピング コードは、以下に示すコードを利用できます (Player がグローバル/アクセス可能なプロパティであると仮定します)。


上記のコンテキストを考えると、正確なリクエストは不可能です。

変数 (プロパティではなく実際の変数) は、それらが宣言されているスコープ、またはスコープ チェーンを通じて解決されるネストされたスコープからのみアクセスできます。これには、 の使用も含まれますeval。これは制限のように思えるかもしれませんが、公開されない限り、スコープ チェーン (およびその変数) が外部からいじられないことも保証します。

returnただし、コンストラクターから明示的なオブジェクトを使用できるという事実を利用する、この楽しいアプローチを検討してください。

var oldMatch = Match
// note this form, else above would be pre-clobbered
Match = function Match (playerRed, playerBlue) {
    var m = new oldMatch(playerRed, playerBlue)
    // either "inject" method here, or save in object for later
    m.myPlayerRed = playerRed
    m.myPlayerBlue = playerBlue
    return m
}

もちろん、これは のようなものを壊しnew Match(...) instanceof Matchます。

ハッピーコーディング。


アップデート:

これは、投稿のリンクで説明されているように、「コンストラクターを新しいコンストラクターでラップし、プロトタイプを等しく設定する」メソッドで動作するように上記を変更したものです。トリックは、グローバル プロパティ名を「盗む」ことです。oldMatchまた、汚染を避けるために「プライベート」に保つようにコードを変更しました。

// note this form, else Match property would be pre-clobbered
Match = (function (oldMatch) {
    function Match (playerRed, playerBlue) {
        oldMatch.call(this, playerRed, playerBlue);
        // either "inject" method here, or save in object for later
        this.myPlayerRed = playerRed
        this.myPlayerBlue = playerBlue
    }
    Match.prototype = oldMatch.prototype
    return Match
})(Match)

最初のコード スニペットとは異なり、これは で機能するはずですnew Match(...) instanceof Matchが、Match オブジェクト メソッド内で行われた特定の仮定によっては、機能しない場合があります。


Player コンストラクターからデータを反転 (「抽出」) する方法の例:

// original -- remember this method will only work
// if Player is used as a property (and not itself a closure'd variable)
function Player (name) {
    this.name = name
}

Player = (function (oldPlayer) {
    function Player (name) {
        oldPlayer.call(this, name)
        var fn = arguments.callee
        fn.recent = fn.recent || []
        fn.recent.push([name, this])         
    }
    Player.prototype = oldPlayer.prototype
    return Player
})(Player)

var p1 = new Player("fred");
var p2 = new Player("barney");

alert("instanceof check? " + p1 instanceof Player)
alert("name check? " + ("barney" == p2.name))

alert(Player.recent.join(","))
Player.recent = [] // reset
于 2011-05-12T09:13:25.607 に答える