Wrapping JavaScript functions allows you add common logic to functions you not control, like the native and external functions. TrackJS エージェントのような多くの JavaScript ライブラリは、その作業を行うために外部関数をラップする必要があります。 ラッパーを追加すると、私たちの API を明示的に呼び出す必要なしに、コード内で Telemetry、エラー、およびログをリッスンできるようになります。
Implementation や一時的なデバッグ ロジックを追加するために、関数をラップしたい場合があります。
Basic Function Wrapping
JavaScript はすばらしく動的なので、単に新しい何かで関数を再定義することにより、関数をラップすることができる。 たとえば、myFunction
:
のラップを考えてみましょう。
このつまらない例では、オリジナルの myFunction
をラップして、ログ メッセージを追加しています。 しかし、処理していないことがたくさんあります:
- 関数の引数をどのように渡すか:
- スコープ (
this
の値) をどのように維持するか: - 戻り値を取得するか:
- もしエラーが発生した場合はどうするか:
- 関数の引数を渡すにはどうするか:
これらを処理するには、もう少し賢いラッピングが必要です。
この例では、単に関数を呼び出しているのではなく、
this
の値と引数a
、b
、c
でcall
していることに注意してください。this
の値は、ラップした関数をアタッチした場所、この例ではWindow
から渡されます。また、関数全体を
try/catch
ブロックで囲み、エラーが発生した場合にカスタム ロジックを起動したり、再スローしたり、デフォルト値を返したりできるようにしました。高度な関数ラッピング
基本的なラッピング例は 90% の時間で機能しますが、TrackJS エージェントのような共有ライブラリを構築する場合、それでは十分ではありません!
- 宣言されていない、あるいは未知の引数についてはどうでしょうか? まず (#1) は、関数に名前を付けました。 冗長に見えますが、ユーザー コードは
function.name
の値をチェックできるので、ラップするときに名前を維持することが重要です。2番目の変更 (#2) は、ラップした関数を呼び出す方法で、
call
の代わりにapply
を使用しました。 これは、実行時に関数に渡されるすべての引数の配列のようなオブジェクトであるarguments
オブジェクトを渡すことができるようにするためです。 これにより、未定義または可変数の引数を持つ可能性のある関数をサポートすることができます。apply
を使用すると、関数署名で定義した引数a
、b
、c
は不要になります。 しかし、元の関数と同じ引数を宣言し続けることで、関数のアリティは維持される。 つまり、Function.length
はシグネチャで定義された引数の数を返し、これは元の関数を反映します。最後の変更 (#3) は、元の関数からユーザー指定のプロパティを私たちのラッピングにコピーします。 具体的には、オブジェクト コンストラクタのような非標準のプロトタイプを持つ関数を正しくラップすることは困難です。 これは、継承によってよりよく解決されるユースケースです。
一般に、関数のプロトタイプを変更することは可能ですが、それは良いアイデアではありません。
環境を尊重する
関数のラップは、JavaScript 環境を計測し操作する多くのパワーを与えてくれます。 あなたには、その力を賢く使う責任があります。 関数ラッパーを構築している場合、ユーザーと操作している環境を尊重するようにしてください。 他のラッパーが存在し、イベントのリスナーが存在し、関数の API が期待されている可能性があります。 軽く踏んで、外部のコードを壊さないようにしましょう。