9

匿名関数がそのコンテキストに基づいて動作する必要があるとしましょう。ただし、それが「ウィンドウ」にバインドされているか、不明なオブジェクトにバインドされているかは異なります。

匿名関数が呼び出されたオブジェクトへの参照を取得するにはどうすればよいですか?

編集、いくつかのコード:

var ObjectFromOtherLibIAmNotSupposedToknowAbout = {
    foo : function() {
        // do something on "this"
    }
}

var function bar(callback) {
     // here I want to get a reference to 
     // ObjectFromOtherLibIAmNotSupposedToknowAbout
     // if ObjectFromOtherLibIAmNotSupposedToknowAbout.foo is passed 
     // as callback
}

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo);

あなたは合法的に尋ねるかもしれません、なぜあなたはそのようなことをしたいのですか?さて、私は最初に配列として渡された引数を解凍したかったのです。*Pythonの" "演算子と同じように:

>>> args = [1,2,3]
>>> def foo(a,b,c) :
        print a,b,c
>>> foo(*args)
1 2 3

SOを掘り下げて、「apply()」を使用するように指示する投稿を見つけました。

function bar(callback, args){
    this[callback].apply(this, args);
}

オブジェクト内の場合は現在の「this」を使用し、そうでない場合は「window」を使用するため、興味深いものです。

しかし、私は問題があると思います:

「bar()」自体がオブジェクト内にある場合、「this」は「bar()」コンテナを参照するため、動作しません。

ところで、スコープをパラメーターとして渡さないようにしたいと思います

もちろん、引数と関数を文字列として連結してevalを使用することもできますが、これは、よりクリーンなものが見つからない場合にのみ使用したいと思います。

もちろん、それが不可能な場合(結局のところ、それは可能性があります)、私はします:

function foo(func, args) 
{
    eval("func("+args.join(", ")+");");
}

編集2:コメントで尋ねられた完全なシナリオ。

私はqunitを使用してJavascriptでユニットテストを実行しています。かっこいいですが、何かが例外を発生させるかどうかを確認する方法がありません。

最も基本的なテストはそのように行われます:

/**
 * Asserts true.
 * @example ok( $("a").size() > 5, "There must be at least 5 anchors" );
 */
function ok(a, msg) {
    _config.Test.push( [ !!a, msg ] );
}

アイデアは次のようなものを作ることです:

jqUnit.prototype.error = function(func, args, msg) 
{
    try 
    {
        eval("func("+args.join(", ")+");");
        config.Test.push( [ false, msg + " expected : this call should have raised an Exception" ] );
    } catch(ex)
    {
        _config.Test.push( [ true, msg ] );
    }
};

私がevalを取り除くことができれば、それは素晴らしいことです。そして、なぜスコープをパラメーターとして使用したくないのですか?手作業で作成するのではなく、スコープの異なる20個の関数を参照するコンテナーをループして、それらすべてをループ内でテストしたい場合があるためです。

4

1 に答える 1

6

eサティス、

唯一の方法は、call または apply メソッドを使用して正しい「コンテキスト」を設定することです。

問題を解決するには、バー関数を変更して、コールバック関数とそのコールバック関数に適用するスコープを受け入れるようにします。

function bar(callback, scope)
{
    callback.apply(scope);
}

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo, ObjectFromOtherLibIAmNotSupposedToknowAbout);

または、「バインド」メソッドを使用できます。

Function.prototype.bind = function(context) {
  var fun = this;
  return function(){
    return fun.apply(context, arguments);
  };
};

これで、bar 関数はそのままにして、呼び出しコードを次のように変更できます。

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo.bind(ObjectFromOtherLibIAmNotSupposedToknowAbout));

編集:

コメントで指摘したように、正しいコールバック関数を渡すのは呼び出し元のコードの責任です。「バー」関数は、使用するスコープ、期間を決定できません。

これを例にとると、

var LibObject = { foo: function() { //use this inside method } };

var fooFunction = LibOjbect.foo;
bar(fooFunction);

どのように範囲を決定するのですか? 現在、「解析」するものは何もなく、「バー」関数を変更してこれを機能させる方法はありません。

于 2009-10-11T14:36:58.333 に答える