概要ご存知のとおり、ES6 では、グローバルで組み込みの非構築可能な Reflect オブジェクトが追加され、一連のインターセプト可能な操作メソッドが提供されます。その 1 つが Reflect.apply() です。従来の ES5 Function.prototype.apply() との類似点と相違点を調べてみましょう。 関数シグネチャMDN 上の 2 つの関数シグネチャは次のとおりです。 Reflect.apply(ターゲット、thisArgument、argumentsList) function.apply(thisArg, [argsArray]) TypeScript で定義されている関数シグネチャは次のとおりです。 名前空間Reflectを宣言する{ 関数を適用します(ターゲット: Function、thisArgument: any、argumentsList: ArrayLike<any>): any; } インターフェース関数{ 適用(this: Function、thisArg: any、argArray?: any): any; } これらはすべて、呼び出された関数に提供される this パラメータとパラメータの配列 (または配列のようなオブジェクト) を受け入れます。 オプションパラメータ最も直感的にわかるのは、function.apply() によって関数に渡される 2 番目のパラメータ「パラメータ配列」がオプションであることです。呼び出された関数にパラメータを渡す必要がない場合は、パラメータを渡さなかったり、null 値や未定義値を渡したりすることはできません。 function.apply() には 2 つのパラメータしかないため、実際には最初のパラメータも省略でき、原理的には実装で未定義の値を取得できます。 (関数() { console.log('test1') }).apply() //テスト1 (関数 () { console.log('test2') }).apply(未定義、[]) //テスト2 (関数 () { console.log('test3') }).apply(未定義、{}) //テスト3 (関数 (テキスト) { console.log(テキスト) }).apply(未定義、['test4']) //テスト4 Reflect.apply() では、すべてのパラメータを渡す必要があります。呼び出された関数にパラメータを渡したくない場合は、空の配列または空の配列のようなオブジェクトを入力する必要があります (純粋な JavaScript では空のオブジェクトも許容されますが、TypeScript の場合は、型チェックに合格するために長さが 0 のキーと値のペアを使用する必要があります)。 Reflect.apply(関数() { console.log('test1') }, 未定義) // スロー: // TypeError: CreateListFromArrayLike が非オブジェクトに対して呼び出されました Reflect.apply(関数() { console.log('test2') }, 未定義、[]) //テスト2 Reflect.apply(関数() { console.log('test3') }, 未定義, {}) //テスト3 Reflect.apply(関数(テキスト) { console.log(テキスト) }, 未定義、['test4']) //テスト4 非厳密モードドキュメントによると、function.apply() の thisArg パラメータは非厳密モードでは異なります。その値が null または undefined の場合、グローバル オブジェクト (ブラウザーのウィンドウ) に自動的に置き換えられ、基本データ型の値が自動的にラップされます (たとえば、リテラル 1 のラップされた値は Number(1) に相当します)。 (関数() { console.log(this) }).apply(null) // ウィンドウ {...} (関数() { console.log(this) }).apply(1) // 数値 { [[PrimitiveValue]]: 1 } (関数() { console.log(this) }).apply(true) // ブール値 { [[PrimitiveValue]]: true } '厳密な使用'; (関数() { console.log(this) }).apply(null) // ヌル (関数() { console.log(this) }).apply(1) // 1 (関数() { console.log(this) }).apply(true) // 真実 しかし、テストの結果、非厳密モードでの上記の動作は Reflect.apply() でも有効であることがわかりましたが、MDN ドキュメントにはこれについて記載されていません。 例外処理Reflect.apply は Function.prototype.apply のカプセル化とみなすことができ、一部の例外判定は同じです。渡されたターゲット関数ターゲットが実際には呼び出し可能ではない、関数ではないなどの場合は、例外がトリガーされます。しかし、異常な症状は異なる場合があります。 ターゲット パラメータに関数ではなくオブジェクトを渡すと、例外が発生します。 Function.prototype.apply() によってスローされる例外のセマンティクスは不明瞭です。文字通りの翻訳は、.call は関数ではないということです。ただし、正しい呼び出し可能な関数オブジェクトを渡すと、エラーは報告されません。これにより、Function.prototype.apply の下に call 属性があるかどうかについて混乱が生じます。 関数プロトタイプを適用します。呼び出し() // スロー: // TypeError: Function.prototype.apply.call は関数ではありません Function.prototype.apply.call(コンソール) // スロー: // TypeError: Function.prototype.apply.call は関数ではありません 関数プロトタイプを適用して呼び出します(console.log) ///- 予想通り、出力は空です Function.prototype.apply() によってスローされる例外はあいまいです。また、ターゲット パラメータに呼び出し不可能なオブジェクトが渡されます。2 番目と 3 番目のパラメータが入力されている場合、スローされる例外の説明は上記とはまったく異なります。 ただし、呼び出し不可能なオブジェクトのみを渡す Reflect.apply() の例外は、すべてのパラメータを指定した Function.prototype.apply() の例外と同じです。 Reflect.apply(コンソール) // スロー: // TypeError: Function.prototype.apply が #<Object> に対して呼び出されましたが、これはオブジェクトであり関数ではありません 正しい呼び出し可能な関数が渡された場合、3 番目のパラメータ配列のパラメータがチェックされます。これは、Reflect.apply() のパラメータ チェックが順次行われることも示しています。 反映.適用(コンソール.ログ) // スロー: // TypeError: CreateListFromArrayLike が非オブジェクトに対して呼び出されました 実用プロキシ以外での使用例はまだ多くありませんが、互換性の問題が徐々に軽減されれば、使用率は徐々に増加すると考えています。 ES6Reflect.apply() の形式は、従来の ES5 の使用法よりも直感的で読みやすく、コード行でどの関数を使用するかがわかりやすくなり、期待される動作を実行できるようになります。 // ES5 Function.prototype.apply.call(<Function>, undefined, [...]) <関数>.apply(undefined, [...]) // ES6 Reflect.apply(<関数>, undefined, [...]) 比較のために、よく使われる Object.prototype.toString を選択してみましょう。 Object.prototype.toString.apply(/ /) // '[オブジェクト正規表現]' Reflect.apply(Object.prototype.toString, //, []) // '[オブジェクト正規表現]' 反対する人もいるかもしれませんが、これは書くのが長くて面倒ではないでしょうか?この点については意見が分かれています。単一の関数を繰り返し呼び出すと、より多くのコードが必要になります。柔軟な使用が必要なシナリオでは、関数型スタイルの方が適しています。関数オブジェクトを指定してパラメータを渡すだけで、期待どおりの結果が得られます。 しかし、この場合、小さな問題が発生する可能性があります。呼び出しごとに新しい空の配列を作成する必要があるのです。現在、ほとんどのデバイスのパフォーマンスは十分に優れているため、プログラマーはこの損失を考慮する必要はありませんが、高パフォーマンスで最適化されていないエンジンのシナリオでは、最初に再利用可能な空の配列を作成する方がよい場合があります。 定数空の引数 = [] 関数 getType(obj) { Reflect.apply() を返す オブジェクト.prototype.toString、 オブジェクト、 空の引数 ) } String.fromCharCode() が呼び出される別のシナリオでは、コード内の文字列を混乱させる可能性があります。 反映.適用( 文字列.fromCharCode、 未定義、 [104、101、108、108、 111、32、119、111、 [114、108、100、33] ) // 'こんにちは世界!' これは、Math.max() などの複数のパラメータを渡すことができる関数の場合に、より便利な場合があります。 定数arr = [1, 1, 2, 3, 5, 8] Reflect.apply(Math.max, 未定義, arr) を適用します。 // 8 Function.prototype.apply.call(Math.max, 未定義, arr) 関数の呼び出し // 8 Math.max.apply(未定義、arr) // 8 ただし、言語標準ではパラメータの最大数は指定されていないため、大きすぎる配列が渡されると、スタック サイズが制限を超えたというエラーが報告される可能性があります。このサイズはプラットフォームやエンジンによって異なります。たとえば、PC 上の node.js は非常に大きなサイズに達する可能性がありますが、携帯電話上の jsC は 65536 に制限される場合があります。 const arr = 新しい配列(Math.floor(2**18)).fill(0) // [ // 0, 0, 0, 0, // ... 262140 件以上 // ] Reflect.apply(Math.max, null, arr) // スロー: // RangeError: 最大コールスタックサイズを超えました 要約する新しい ES6 標準で提供される Reflect.apply() は、より規則的で使いやすくなっています。次の機能があります。 1. 直感的で読みやすく、呼び出される関数はパラメータ内に配置され、関数型スタイルに近いです。 2. 例外処理は一貫しており、明確である。 3. すべてのパラメータを渡す必要があり、コンパイル時のエラーチェックと型推論がより使いやすくなります。 現在、vue.js 3 もレスポンシブ システムで Proxy と Reflect を多用しています。近い将来、フロントエンドの世界で Reflect が活躍することを期待しています。 上記は、ES5とES6のapplyの違いの詳細な分析です。ES5とES6の違いの詳細については、123WORDPRESS.COMの他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
<<: Mysql5.7.17 winx64.zip 解凍バージョンのインストールと設定のグラフィックチュートリアル
>>: Nginx で https をアップグレードする方法
今日は、CSS を使用して左上の三角形を記述するいくつかの方法を紹介します。概略図(幅と高さを60p...
実際、上記の 3 つの表はいずれも 3 行 3 列です。区切り線を非表示にするコツはルールにあります...
目次1. 要件の説明2. アイデアの概要1. 延長を要求する2. アイデアの概要3. SQLコード1...
目次1. 主キーが存在する2. 主キーはないが、一意のインデックスが存在する3. 共同主キーまたは共...
目次1. 基本的な使い方2. 指示の動作原理2.1. 初期化2.2 テンプレートのコンパイル2.3....
今日、vue3+viteプロジェクトの実践で、svgを使用する場合、以前の記述方法が使用できないこと...
目次1. Dockerをインストールする2. コードを書く3. Dockerfileを書く4. 画像...
今回はReact-Flaskフレームワーク上でアップロードコンポーネントを開発するスキルについてお話...
MySQL 8.0 の新機能は次のとおりです。 Unicode 9.0 をすぐに完全にサポートウィン...
目次1要素オフセットシリーズ1.1 オフセットの概要1.2 オフセットとスタイルの違い視覚領域クライ...
導入: springboot プロジェクトを実行する Docker の構成は実は非常にシンプルで、L...
Windows システムに仮想マシンをインストールするには、 VMware Workstationソ...
目次インストール不要のMySQLバージョン1. インストール パッケージをダウンロードします。 2....
公式ドキュメント: https://nginx.org/en/linux_packages.html...
まずはコードを見てみましょう <フォーム id="uploadFileForm2&q...