this
保存します。 簡単に聞こえますが、誰もがそれが何を意味するのか、それがなければ以前はどれほど難しかったのか理解できますか?
たとえば、次のような関数を記述することができます。
public class TestClass { var property : Number; function updateValue(value : Number) : void { TestClass(this).property = value; } }
そしてどこにでも転送します:
var func : Function = new TestClass().updateValue; func(555);
確かに、これで呼び出される場所には必ず
TestClass
クラスのインスタンスがあります。 しかし、私はこれについて話しているのではなく、 Action Scriptの関数で実行できるより興味深いアクションがあります。それらを検討します。
非同期呼び出し
ほとんどの場合、サーバー上のリモートメソッドを呼び出し、この呼び出しの結果を処理するタスクに直面していました。 サービスクラスがあるとしましょう
ServerService
ServerService
は、応答を処理する関数へのコンストラクター参照を受け取り、ソースオブジェクトのプロパティを更新する一般的なタスクを実行します。
class Example { function updateItem(item : SomeObject) : void { _tempObject = item; new ServerService(onGetResult).getResult(item.startValue); } function onGetResult(result : Object) : void { _tempObject.endValue = result; } private var _tempObject : SomeObject; }
すべてが正しく書かれていますが、なぜそんなに複雑なのですか? スマートコードでこのナンセンスを単純化しましょう:
function updateItem(item : SomeObject) : void { new ServerService(onGetResult).getResult(item.startValue); function onGetResult(result : Object) : void { item.endValue = result; } }
この場合、
onGetResult
関数は、
onGetResult
関数のすべての変数とその
item
引数にアクセスできます。 多くの場合、この手法はコードの量を減らし、非同期性の否定的な意味合いを取り除くことができます。 ところで、
this
関数では
onGetResult
は
Example
インスタンスではなく、単に
global
ます。
複数の非同期呼び出し
さらに興味深いのは、いくつかの非同期要求をループで作成し、それに応じて各応答を処理する必要がある場合です。次に例を示します。
function updateItems(items : ArrayCollection) : void { for each (var item : SomeObject in items) { new ServerService(onGetResult).getResult(item.startValue); } function onGetResult(result : Object) : void { item.endValue = result; } }
このコードでは、望ましい結果が得られません。 その時点で、サーバーが回答を返すと、
item
変数は
items
コレクションの最後の要素を参照し、すべてのデータはそれだけに割り当てられます。 そのような状況では、関数の保存されたコンテキストも親変数のスコープも役立たず、何か他のものが必要です。
多くの場合、いわゆる
Loader
使用できます。
function updateItems(items : ArrayCollection) : void { for each (var item : SomeObject in items) { new ValueLoader(item); } } class ValueLoader { public function ValueLoader(item : SomeObject) { new ServerService(onGetResult).getResult(item.startValue); function onGetResult(result : Object) : void { item.endValue = result; } } }
関数のコンテキストは、サーバーが応答した後に
item
を保存して更新するのに十分ではないため、関数のラッパーを作成します-コンテキストで必要なすべてを記憶できるクラスです。 クラスコンストラクターはまだ同じ関数であるため、
item
引数は問題なく
onGetResult
関数で使用できます。
標準化されたContextFunction
最終的に、すべての種類のローダーを大量に作成したくない場合は、ユニバーサルタイプ(繰り返し使用するパターン)を導入できます。
class ContextFunction { public function ContextFunction(targetFunction : Function, ... args) { _contextArgumnets = args; _targetFunction = targetFunction; } public function func(... args) : void { var targetArguments : Array = args.concat(_contextArgumnets); _targetFunction.apply(this, targetArguments); } private var _contextArgumnets : Array; private var _targetFunction : Function; }
ソリューションの本質は、
ContextFunction
インスタンス
ContextFunction
、特定のロジックを持つ関数への参照と、誰かが呼び出したときに関数が受け取る未定義の引数のセットによって決定されることです。 また、呼び出し元のエンティティの要求に応じて、これらの引数に何か他のものが追加されます。 明確にするための例を考えてみましょう。
function updateItems(items : ArrayCollection) : void { for each (var item : SomeObject in items) { new ServerService(new ContextFunction(onGetResult, item).func). getResult(item.startValue); } } function onGetResult(result : Object, item : SomeObject) : void { item.endValue = result; }
これは本質的には
Loader
場合と同じ解決策であり、より普遍的なものです。
ContextFunction
インスタンスは
onGetResult
保存し
onGetResult
。これは、サーバーからの応答と、サーバー値が要求された
item
へのリンクを受け取ります。 つまり、一般に関数のコンテキストを放棄し、補助クラスのインスタンスを使用して目的の値を保存します。
結論として、これらのトリックはすべて私が実際に非常に頻繁かつ効果的に使用していることを保証できます。 これは指の問題ではありません。