web-dev-qa-db-ja.com

Javascriptリフレクション

Javascriptオブジェクトのすべてのメソッド(プライベート、特権、またはパブリック)を内部から取得する方法はありますか?サンプルオブジェクトは次のとおりです。

_var Test = function() {
// private methods
    function testOne() {}
    function testTwo() {}
    function testThree() {}
// public methods
    function getMethods() {
      for (i in this) {
        alert(i); // shows getMethods, but not private methods
      }
    }
    return { getMethods : getMethods }
}();

// should return ['testOne', 'testTwo', 'testThree', 'getMethods']
Test.getMethods();
_

現在の問題はgetMethods()のコードです。簡略化された例では、パブリックメソッドのみが返され、プライベートメソッドには返されません。

編集:私のテストコードは、私が得たいと思っていることを過度に複雑にしているかもしれません(またはそうでないかもしれません)。次の場合:

_function myFunction() {
  var test1 = 1;
  var test2 = 2;
  var test3 = 3;
} 
_

myFunction()内からmyFunction()に存在する変数を見つける方法はありますか。擬似コードは次のようになります。

_function myFunction() {
  var test1 = 1;
  var test2 = 2;
  var test3 = 3;

  alert(current.properties); // would be Nice to get ['test1', 'test2', 'test3']
}
_
28
Owen

これらのメソッドが隠されている技術的な理由は2つあります。

まず、Testオブジェクトでメソッドを実行すると、「this」は、 Module Pattern ごとにパブリックメソッドを含む無名関数の最後に返される型指定されていないオブジェクトになります。

次に、メソッドtestOne、testTwo、およびtestThreeは特定のオブジェクトにアタッチされておらず、無名関数のコンテキストにのみ存在します。メソッドを内部オブジェクトにアタッチしてから、パブリックメソッドを介して公開することもできますが、元のパターンほどクリーンではなく、このコードをサードパーティから取得した場合は役に立ちません。

結果は次のようになります。

var Test = function() {
    var private = {
        testOne : function () {},
        testTwo : function () {},
        testThree : function () {}
    };

    function getMethods() {
        for (i in this) {
            alert(i); // shows getMethods, but not private methods
        }
        for (i in private) {
            alert(i); // private methods
        }
    }
    return { getMethods : getMethods }
}();

// will return ['getMethods', 'testOne', 'testTwo', 'testThree']
Test.getMethods();

編集:

残念だけど違う。ローカル変数のセットには、単一の自動キーワードを介してアクセスすることはできません。

「var」キーワードを削除すると、それらはグローバルコンテキスト(通常はウィンドウオブジェクト)に添付されますが、私が知っている唯一の動作は、あなたが説明しているものと似ています。ただし、そうすると、そのオブジェクトには他にも多くのプロパティとメソッドがあります。

28
Kevin Gorski

から http://netjs.codeplex.com/SourceControl/changeset/view/91169#1773642

//Reflection

~function (extern) {

var Reflection = this.Reflection = (function () { return Reflection; });

Reflection.prototype = Reflection;

Reflection.constructor = Reflection;

Reflection.getArguments = function (func) {
    var symbols = func.toString(),
        start, end, register;
    start = symbols.indexOf('function');
    if (start !== 0 && start !== 1) return undefined;
    start = symbols.indexOf('(', start);
    end = symbols.indexOf(')', start);
    var args = [];
    symbols.substr(start + 1, end - start - 1).split(',').forEach(function (argument) {
        args.Push(argument);
    });
    return args;
};

extern.Reflection = extern.reflection = Reflection;

Function.prototype.getArguments = function () { return Reflection.getArguments(this); }

Function.prototype.getExpectedReturnType = function () { /*ToDo*/ }

} (this);
5
Jay

Javascriptには、プライベートなものという概念は実際にはありません。そのため、javascriptにはリフレクションAPI自体がありません。使用している手法では、アクセスできなくなるほどプライベートにはなりません。それらは非公開ではなく、非表示になっています。それらのメソッドを手動でどこかに置くことで何かを管理できると思います。

2
sblundy

関数の定義方法を少し変更するだけで、必要なことを実現できます。関数の実際の実装をオブジェクトリテラルでラップすると、次のようになります。

(function() {
    var obj = {
    // private methods
    testOne: function () {},
    testTwo : function () {},
    testThree: function () {},
    // public methods
    getMethods : function () {
      for (i in this) {
        alert(i); // shows getMethods, but not private methods
      }
    }
    };
    return { getMethods : function(){return obj.getMethods();} }
})();
1
Rune FS

テストコードの問題の一部は、Testがreturnステートメントによって作成されたオブジェクトであるということです: "{ getMethods : getMethods } "testOne、testTwo、またはtestThreeメソッドはありません。代わりに、元のgetMethods関数と同じ名前空間内でのみ使用できます。

1
eswald

var that = this;トリックを使用できます:

var Test = function() {
    var that = this;
    function testOne() {}
    function testTwo() {}
    function testThree() {}
    function getMethods() {
      for (i in that) {
        alert(i);
      }
    }
    return { getMethods : getMethods }
}();
1
small_jam

そのようにgetMethods()を呼び出すと、静的ではありませんか?確かに、thisが期待どおりに機能するには、クラスを適切に初期化する必要がありますか?

var t = new Test();
t.getMethods();

それでも問題が解決しない場合は、 JS Serializer をご覧ください。しばらく前にデバッグに使用しましたが、プライベート変数で機能したと思います。

0
Oli