How to Correctly Wrap a JavaScript Function

, Author

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の値と引数 abccall していることに注意してください。 this の値は、ラップした関数をアタッチした場所、この例では Window から渡されます。

    また、関数全体を try/catch ブロックで囲み、エラーが発生した場合にカスタム ロジックを起動したり、再スローしたり、デフォルト値を返したりできるようにしました。

    高度な関数ラッピング

    基本的なラッピング例は 90% の時間で機能しますが、TrackJS エージェントのような共有ライブラリを構築する場合、それでは十分ではありません!

    • 宣言されていない、あるいは未知の引数についてはどうでしょうか? まず (#1) は、関数に名前を付けました。 冗長に見えますが、ユーザー コードは function.name の値をチェックできるので、ラップするときに名前を維持することが重要です。

      2番目の変更 (#2) は、ラップした関数を呼び出す方法で、call の代わりに apply を使用しました。 これは、実行時に関数に渡されるすべての引数の配列のようなオブジェクトである arguments オブジェクトを渡すことができるようにするためです。 これにより、未定義または可変数の引数を持つ可能性のある関数をサポートすることができます。

      applyを使用すると、関数署名で定義した引数 abc は不要になります。 しかし、元の関数と同じ引数を宣言し続けることで、関数のアリティは維持される。 つまり、Function.length はシグネチャで定義された引数の数を返し、これは元の関数を反映します。

      最後の変更 (#3) は、元の関数からユーザー指定のプロパティを私たちのラッピングにコピーします。 具体的には、オブジェクト コンストラクタのような非標準のプロトタイプを持つ関数を正しくラップすることは困難です。 これは、継承によってよりよく解決されるユースケースです。

      一般に、関数のプロトタイプを変更することは可能ですが、それは良いアイデアではありません。

      環境を尊重する

      関数のラップは、JavaScript 環境を計測し操作する多くのパワーを与えてくれます。 あなたには、その力を賢く使う責任があります。 関数ラッパーを構築している場合、ユーザーと操作している環境を尊重するようにしてください。 他のラッパーが存在し、イベントのリスナーが存在し、関数の API が期待されている可能性があります。 軽く踏んで、外部のコードを壊さないようにしましょう。

コメントを残す

メールアドレスが公開されることはありません。