多くの JavaScript 組み込み関数は、任意の数の引数をサポートしています。
例えば:
Math.max(arg1, arg2, ..., argN)
– 引数の最大のものを返します。
Object.assign(dest, src1, ..., srcN)
– プロパティをsrc1..N
からdest
にコピーします。
…等々。
この章では、同じことを行う方法を学びます。また、配列をパラメータとして関数などに渡す方法も説明します。
...
関数は、定義方法に関係なく、任意の数の引数を指定して呼び出すことができます。
ここのように:
関数 sum(a, b) { a + b を返します。 } アラート(合計(1, 2, 3, 4, 5) );
「過剰な」引数によるエラーは発生しません。ただし、もちろん結果では最初の 2 つだけがカウントされるため、上記のコードの結果は3
なります。
残りのパラメータは、3 つのドット...
の後にパラメータを含む配列の名前を使用することで関数定義に含めることができます。ドットは文字通り「残りのパラメータを配列に集める」ことを意味します。
たとえば、すべての引数を配列args
に収集するには、次のようにします。
function sumAll(...args) { // args は配列の名前です 合計 = 0 とします。 for (arg of args) sum += arg; 合計を返します。 } アラート( sumAll(1) ); // 1 アラート( sumAll(1, 2) ); // 3 アラート( sumAll(1, 2, 3) ); // 6
最初のパラメータを変数として取得し、残りのみを収集することを選択できます。
ここで、最初の 2 つの引数は変数に入れられ、残りはtitles
配列に入れられます。
function showName(名、姓、...タイトル) { alert( firstName + ' ' + lastName ); // ジュリアス・シーザー // 残りはタイトル配列に入れられます // つまり、タイトル = ["執政官", "皇帝"] アラート( タイトル[0] ); // 領事 アラート(タイトル[1]); // インペレーター アラート(タイトル.長さ); // 2 } showName("ジュリアス"、"シーザー"、"執政官"、"皇帝");
残りのパラメータは最後にある必要があります
残りのパラメータは残りの引数をすべて収集するため、次の場合は意味をなさず、エラーが発生します。
function f(arg1, ...rest, arg2) { // ...rest の後の arg2 ?! // エラー }
...rest
常に最後でなければなりません。
すべての引数をインデックスごとに含む、 arguments
という名前の特別な配列のようなオブジェクトもあります。
例えば:
関数 showName() { アラート(引数.長さ); アラート( 引数[0] ); アラート( 引数[1] ); // 反復可能です // for(引数の arg を指定)alert(arg); } // 表示: 2、ジュリアス、シーザー showName("ジュリアス", "シーザー"); // 表示: 1、Ilya、未定義 (2 番目の引数なし) showName("イリヤ");
昔は言語に残りのパラメータは存在せず、 arguments
使用することが関数のすべての引数を取得する唯一の方法でした。そしてそれは今でも機能しており、古いコードで見つけることができます。
ただし、 arguments
配列に似ていて反復可能であるにもかかわらず、配列ではないという欠点があります。配列メソッドはサポートされていないため、たとえばarguments.map(...)
を呼び出すことはできません。
また、常にすべての引数が含まれます。残りのパラメーターの場合のように、部分的にキャプチャすることはできません。
したがって、これらの機能が必要な場合は、残りのパラメーターが優先されます。
アロー関数には"arguments"
がありません
アロー関数からarguments
オブジェクトにアクセスすると、外側の「通常の」関数から引数オブジェクトが取得されます。
以下に例を示します。
関数 f() { showArg = () =>alert(arguments[0]); showArg(); } f(1); // 1
覚えているように、アロー関数には独自のthis
がありません。これで、特別なarguments
オブジェクトも持たないことがわかりました。
パラメーターのリストから配列を取得する方法を説明しました。
しかし、場合によってはまったく逆のことを行う必要があります。
たとえば、リストから最大の数値を返す組み込み関数 Math.max があります。
アラート( Math.max(3, 5, 1) ); // 5
ここで、配列[3, 5, 1]
があるとします。これを使ってMath.max
呼び出すにはどうすればよいでしょうか?
Math.max
単一の配列ではなく数値引数のリストを期待しているため、「そのまま」渡しても機能しません。
arr = [3, 5, 1] とします。 アラート( Math.max(arr) ); // NaN
そして確かに、コードMath.max(arr[0], arr[1], arr[2])
内の項目を手動でリストすることはできません。項目がいくつあるかわからない可能性があるからです。スクリプトを実行すると、たくさんのものが存在することもあれば、まったく存在しないこともあります。そしてそれは醜いものになるでしょう。
スプレッド構文を助けてください!これも...
使用する REST パラメータに似ていますが、まったく逆の動作をします。
...arr
関数呼び出しで使用されると、反復可能なオブジェクトarr
引数のリストに「展開」されます。
Math.max
の場合:
arr = [3, 5, 1] とします。 alert( Math.max(...arr) ); // 5 (spread は配列を引数のリストに変換します)
この方法で複数の反復可能オブジェクトを渡すこともできます。
arr1 = [1, -2, 3, 4]; とします。 arr2 = [8, 3, -8, 1]; とします。 alert( Math.max(...arr1, ...arr2) ); // 8
スプレッド構文と通常の値を組み合わせることもできます。
arr1 = [1, -2, 3, 4]; とします。 arr2 = [8, 3, -8, 1]; とします。 alert( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25
また、スプレッド構文を使用して配列を結合することもできます。
arr = [3, 5, 1] とします。 arr2 = [8, 9, 15] とします。 マージさせます = [0, ...arr, 2, ...arr2]; アラート(マージ); // 0,3,5,1,2,8,9,15 (0、次に arr、次に 2、次に arr2)
上記の例では、スプレッド構文を示すために配列を使用しましたが、任意の反復可能オブジェクトを使用できます。
たとえば、ここではスプレッド構文を使用して文字列を文字の配列に変換します。
let str = "こんにちは"; アラート( [...str] ); // こんにちは
スプレッド構文は、 for..of
と同じ方法で、内部的に反復子を使用して要素を収集します。
したがって、文字列の場合、 for..of
文字を返し、 ...str
"H","e","l","l","o"
になります。文字のリストは配列初期化子[...str]
に渡されます。
この特定のタスクでは、 Array.from
使用することもできます。これは、反復可能 (文字列など) を配列に変換するためです。
let str = "こんにちは"; // Array.from はイテラブルを配列に変換します alert( Array.from(str) ); // こんにちは
結果は[...str]
と同じになります。
ただし、 Array.from(obj)
と[...obj]
の間には微妙な違いがあります。
Array.from
配列のようなものと反復可能なものの両方で動作します。
スプレッド構文は反復可能オブジェクトでのみ機能します。
したがって、何かを配列に変換するタスクでは、 Array.from
がより汎用的になる傾向があります。
以前Object.assign()
について話したときのことを覚えていますか?
スプレッド構文でも同じことを行うことができます。
arr = [1, 2, 3] とします。 arrCopy = [...arr]; にします。 // 配列をパラメータのリストに展開します // 次に結果を新しい配列に代入します // 配列の内容は同じですか? alert(JSON.stringify(arr) === JSON.stringify(arrCopy)); // 真実 // 配列は等しいか? アラート(arr === arrCopy); // false (同じ参照ではありません) // 初期配列を変更してもコピーは変更されません。 arr.push(4); アラート(arr); // 1、2、3、4 アラート(arrCopy); // 1、2、3
同じことを行ってオブジェクトのコピーを作成することも可能であることに注意してください。
obj = { a: 1, b: 2, c: 3 }; とします。 let objCopy = { ...obj }; // オブジェクトをパラメータのリストに展開します // その後、結果を新しいオブジェクトで返します // オブジェクトの内容は同じですか? alert(JSON.stringify(obj) === JSON.stringify(objCopy)); // 真実 // オブジェクトは等しいか? アラート(obj === objCopy); // false (同じ参照ではありません) // 初期オブジェクトを変更してもコピーは変更されません。 obj.d = 4; アラート(JSON.stringify(obj)); // {"a":1,"b":2,"c":3,"d":4} アラート(JSON.stringify(objCopy)); // {"a":1,"b":2,"c":3}
オブジェクトをコピーするこの方法はlet objCopy = Object.assign({}, obj)
や配列のlet arrCopy = Object.assign([], arr)
よりもはるかに短いため、できる限りこの方法を使用することを好みます。
コード内に"..."
がある場合、それは残りのパラメータまたはスプレッド構文のいずれかです。
それらを区別する簡単な方法があります。
...
関数パラメータの最後にある場合、それは「残りのパラメータ」となり、引数リストの残りを配列に集めます。
関数呼び出しなどで...
発生すると、それは「スプレッド構文」と呼ばれ、配列をリストに展開します。
使用パターン:
残りのパラメーターは、任意の数の引数を受け入れる関数を作成するために使用されます。
スプレッド構文は、通常多くの引数のリストを必要とする関数に配列を渡すために使用されます。
これらを組み合わせると、リストとパラメーターの配列の間を簡単に移動できるようになります。
関数呼び出しのすべての引数は、「古いスタイル」のarguments
、つまり配列のような反復可能オブジェクトでも使用できます。