JavaScript のスプレッド演算子とレスト演算子の違いの詳細な説明

JavaScript のスプレッド演算子とレスト演算子の違いの詳細な説明

JavaScript では、3 つのドット (...) 記号をレスト演算子およびスプレッド演算子として使用しますが、これら 2 つの演算子には違いがあります。

主な違いは、REST 演算子はユーザーが指定した特定の値の残りを JavaScript 配列に格納するのに対し、スプレッド演算子は反復可能なオブジェクトを単一の要素に拡張することです。

たとえば、次のコードでは、rest 演算子を使用して配列に部分的な値を格納します。

// rest を使用して、ユーザーが指定した特定の値の残りを配列で囲みます。
関数 myBio(firstName, lastName, ...otherInfo) { 
 その他の情報を返します。
}

// 5 つの引数をパラメータに渡しながら myBio 関数を呼び出します。
myBio("Oluwatobi", "Sofela", "CodeSweetly", "Web 開発者", "男性");

// 上記の呼び出しは以下を返します:
["CodeSweetly", "Web 開発者", "男性"]

実行結果を見る

上記のコードでは、...otherInfo を使用して、myBio() 関数に渡されるパラメーターの残りの部分、「CodeSweetly」、「We Developer」、および「Male」を配列に格納します。

次に、スプ​​レッド演算子を使用する次の例を見てみましょう。

 // 3 つのパラメータを持つ関数を定義します。
関数 myBio(firstName, lastName, company) { 
 `${firstName} ${lastName} が ${company} を実行します` を返します。
}

// スプレッドを使用して配列の項目を個々の引数に展開します。
myBio(...["Oluwatobi", "Sofela", "CodeSweetly"]);

// 上記の呼び出しは以下を返します:
「Oluwatobi Sofela が CodeSweetly を運営しています」

実行結果を見る

上記のコードでは、スプレッド演算子 (...) を使用して、配列 ["Oluwatobi", "Sofela", "CodeSweetly"] の内容を 1 つずつ展開し、関数 myBio() のパラメーターに渡します。

レスト演算子とスプレッド演算子についてよく知らない場合でも心配しないでください。この記事の後半で紹介します。

次の章では、JavaScript で REST 演算子とスプレッド演算子がどのように機能するかについて詳しく説明します。

レスト演算子とは何ですか?

前述のように、rest 演算子は、ユーザーが指定した特定の値の残りを JavaScript 配列に格納します。構文は次のとおりです。

 ...あなたの価値観

上記のコード内の 3 つのドット (...) は、残余演算子を表すために使用されます。

残り演算子は、配列に埋め込む値を表すために使用されます。残余演算子は関数定義の最後の引数でのみ使用できることに注意してください。

JavaScript 関数で REST 演算子はどのように機能しますか?

JavaScript 関数では、関数の最後のパラメータの前に rest 演算子が使用されます。次のコードに示すように:

 // 2 つの通常のパラメータと 1 つの残りのパラメータを持つ関数を定義します。
関数 myBio(firstName, lastName, ...otherInfo) { 
  その他の情報を返します。
}

ここで、rest 演算子は、ユーザーが otherInfo パラメータに指定した値を配列に追加するように JavaScript プログラムに指示します。次に、配列を otherInfo パラメータに割り当てます。

したがって、残りのパラメータを ...otherInfo と呼びます。

呼び出し時に関数に渡される実際のパラメータの残りのパラメータはオプションであることに注意することが重要です。

別の例:

 // 2 つの通常のパラメータと 1 つの残りのパラメータを持つ関数を定義します。
関数 myBio(firstName, lastName, ...otherInfo) { 
 その他の情報を返します。
}

// 5 つの引数をパラメータに渡しながら myBio 関数を呼び出します。
myBio("Oluwatobi", "Sofela", "CodeSweetly", "Web 開発者", "男性");

// 上記の呼び出しは以下を返します:
["CodeSweetly", "Web 開発者", "男性"]

実行結果を見る

上記のコードでは、myBio() 関数を呼び出すときに 5 つのパラメータが渡されますが、myBio() 関数の実際のパラメータは 3 つだけです。つまり、パラメーター「Oluwatobi」と「Sofela」はそれぞれ firstName と lastName に渡され、その他のパラメーター (「CodeSweetly」、「Web Developer」、および「Male」) は残りのパラメーター otherInfo に渡されます。したがって、関数 myBio() によって返される結果は ["CodeSweetly", "Web Developer", "Male"] となり、これが残りのパラメータ otherInfo の内容となります。

知らせ!残りのパラメータを含む関数本体では「use strict」を使用できません

残余パラメータ、デフォルトパラメータ、またはパラメータ分解を含む関数本体内では、「use strict」ディレクティブを使用できないことに注意してください。そうでない場合、JavaScript は構文エラーを報告します。

次のコードを考えてみましょう。

 // 1 つの残りパラメータを持つ関数を定義します。
関数 printMyName(...値) {
 「厳密な使用」;
 戻り値;
}

// 上記の定義は以下を返します:
「キャッチされない構文エラー: 単純でないパラメータ リストを持つ関数内の不正な 'use strict' ディレクティブ」

注意: 「use strict」は、スクリプト全体または囲むスコープが厳密モードの場合にのみ、関数本体の外側に配置できます。

関数内での残余演算子の動作がわかったので、パラメータ分解での動作を見てみましょう。

引数の分割において、rest 演算子はどのように機能しますか?

通常、rest 演算子は、パラメータ分割代入の最後の変数の前に使用されます。次に例を示します。

 // 2 つの通常の変数と 1 つの残りの変数を持つ分割配列を定義します。
const [firstName, lastName, ...otherInfo] = [
 「Oluwatobi」、「Sofela」、「CodeSweetly」、「Web 開発者」、「男性」
];

// otherInfo 変数を呼び出します:
コンソールにログ出力します。 

// 上記の呼び出しは以下を返します:
["CodeSweetly", "Web 開発者", "男性"]

実行結果を見る

ここでの残り演算子 (...) は、JavaScript プログラムに、ユーザーが指定した残りの値を配列に追加するように指示します。次に、配列を otherInfo 変数に割り当てます。

したがって、ここでは残りの変数を ...otherInfo と呼びます。

別の例:

 // 2 つの通常の変数と 1 つの残りの変数を持つ分割オブジェクトを定義します。
const { firstName, lastName, ...otherInfo } = {
 ファーストネーム: "オルワトビ",
 姓: "ソフェラ", 
 会社名: "CodeSweetly",
 職業: 「Web開発者」、
 性別: 「男性」
}

// otherInfo 変数を呼び出します:
コンソールにログ出力します。

// 上記の呼び出しは以下を返します:
{companyName: "CodeSweetly", 職業: "Web 開発者", 性別: "男性"}

実行結果を見る

上記のコードでは、rest 演算子がプロパティ オブジェクト (配列ではない) を otherInfo 変数に割り当てることに注意してください。つまり、オブジェクトを分解するときに rest 演算子を使用すると、配列ではなくプロパティ オブジェクトが生成されます。

ただし、配列または関数を分解するときに rest 演算子を使用すると、配列リテラルが生成されます。

JavaScript 引数と REST パラメータにはいくつかの違いがあることに気づいたかもしれません。その違いについて見てみましょう。

JavaScript 引数と REST パラメータの違いは何ですか?

以下に、JavaScript 引数と REST パラメータの違いをいくつか示します。

違い 1: arguments オブジェクトは配列のようなオブジェクトですが、実際の配列ではありません。
JavaScript 引数オブジェクトは真の配列ではないことに注意してください。これは、配列が持つプロパティを一切持たない、配列のようなオブジェクトです。

残りのパラメータは実際の配列であり、配列用の任意のメソッドを使用できます。たとえば、残りの引数に対して sort()、map()、forEach()、または pop() メソッドを使用できます。これらのメソッドは引数オブジェクトでは使用できません。

違い 2: 引数オブジェクトは矢印関数では使用できません。引数オブジェクトは矢印関数では使用できませんが、残りのパラメータは矢印関数を含むすべての関数で使用できます。

違い 3: 残りパラメータを優先する 特に ES6 互換のコードを書くときは、引数オブジェクトよりも残りパラメータを優先します。

レスト演算子がどのように機能するかを確認したので、スプレッド演算子について説明し、レスト演算子との違いを確認しましょう。

スプレッド演算子とは何ですか? JavaScript ではどのように機能しますか?

スプレッド演算子 (...) は反復可能なオブジェクトを個々の要素に拡張します。

スプレッド演算子は、配列リテラル、関数呼び出し、初期化されたプロパティ オブジェクトに適用できます。反復可能なオブジェクトの値を 1 つずつ個別の要素に展開します。実際、これはレスト演算子の逆です。

スプレッド演算子は、配列リテラル、関数呼び出し、または初期化されたプロパティ オブジェクト内で使用される場合にのみ機能することに注意してください。

実際の例をいくつか見てみましょう。

例1: 配列リテラルにおけるスプレッド演算子の動作

const myName = ["Sofela", "is", "my"];
const aboutMe = ["Oluwatobi", ...myName, "名前。"];

console.log(aboutMe);

// 上記の呼び出しは以下を返します:
[「オルワトビ」、「ソフェラ」、「は」、「私の」、「名前」です。]

実行結果を見る

上記のコードでは、スプレッド演算子 (...) が myName 配列を aboutMe にコピーします。

知らせ:

  • myName への変更は aboutMe に反映されません。 myName配列内のすべての値はプリミティブであるためです。スプレッド演算子は、元の配列要素への参照を作成せずに、myName 配列の内容を aboutMe にコピーして貼り付けるだけです。
  • スプレッド演算子は浅いコピーのみを実行します。したがって、myName 配列に非プリミティブ値が含まれている場合、JavaScript は myName と aboutMe の間に参照を作成します。スプレッド演算子がプリミティブ値と非プリミティブ値を処理する方法の詳細については、ここを参照してください。
  • たとえば、スプレッド演算子を使用して myName 配列の内容をコピーしなかったとします。次のコード行を記述します。const aboutMe = [ "Oluwatobi", myName, "name." ] この場合、JavaScript は myName への参照を割り当てるため、myName 配列に加えられたすべての変更が aboutMe 配列に反映されます。

例2: スプレッド演算子を使用して文字列を配列に変換する方法

const myName = "オルワトビ・ソフェラ";

コンソールにログ出力します。

// 上記の呼び出しは以下を返します:
[ "O"、"l"、"u"、"w"、"a"、"t"、"o"、"b"、"i"、" "、"S"、"o"、"f"、"e"、"l"、"a" ]

実行結果を見る

上記のコードでは、配列リテラル内でスプレッド演算子 ( [...]) を使用して、myName 文字列の値を配列に展開します。したがって、文字列「Oluwatobi Sofela」の内容は、配列 [「O」、「l」、「u」、「w」、「a」、「t」、「o」、「b」、「i」、「」、「S」、「o」、「f」、「e」、「l」、「a」] に展開されます。

例3: 関数呼び出しにおけるスプレッド演算子の動作

定数数値 = [1, 3, 5, 7];

関数addNumbers(a, b, c, d) {
 a + b + c + d を返します。
}

console.log(addNumbers(...数値));

// 上記の呼び出しは以下を返します:
16

実行結果を見る

上記のコードでは、スプレッド演算子を使用して、numbers 配列の内容を展開し、それを addNumbers() 関数のパラメーターに渡します。数値配列に 4 つ以上の要素がある場合、JavaScript は最初の 4 つの要素のみをパラメーターとして addNumbers() 関数に渡し、残りは無視します。

他にもいくつか例を挙げます。

定数数値 = [1, 3, 5, 7, 10, 200, 90, 59];

関数addNumbers(a, b, c, d) {
 a + b + c + d を返します。
}

console.log(addNumbers(...数値));

// 上記の呼び出しは以下を返します:
16

実行結果を見る

const myName = "オルワトビ・ソフェラ";

関数spellName(a, b, c) {
 a + b + c を返します。
}

console.log(spellName(...myName)); // 戻り値: "Olu"

console.log(spellName(...myName[3])); // 戻り値: "wundefinedundefined"

console.log(spellName([...myName])); // 戻り値: "O,l,u,w,a,t,o,b,i, ,S,o,f,e,l,aundefinedundefined"

console.log(spellName({...myName})); // 戻り値: "[object Object]undefinedundefined"

実行結果を見る

例4: オブジェクトリテラルにおけるスプレッド演算子の動作

const myNames = ["オルワトビ", "ソフェラ"];
const bio = { ...myNames、実行場所: "codesweetly.com" };

コンソールログ(バイオ);

// 上記の呼び出しは以下を返します:
{ 0: "Oluwatobi"、1: "Sofela"、実行: "codesweetly.com" }

実行結果を見る

上記のコードでは、bio オブジェクト内でスプレッド演算子を使用して、配列 myNames の値を個々の属性に展開します。

スプレッド演算子について知っておくべきこと

スプレッド演算子を使用する際に留意すべき 3 つの基本的な情報を以下に示します。

1. スプレッド演算子はオブジェクトリテラルの値を展開できない

属性オブジェクトは反復不可能なオブジェクトであるため、スプレッド演算子を使用してその値を展開することはできません。ただし、スプレッド演算子を使用して、あるオブジェクトのプロパティを別のオブジェクトに複製することができます。

次の例を考えてみましょう。

 const myName = { firstName: "オルワトビ", lastName: "ソフェラ" };
const bio = { ...myName、ウェブサイト: "codesweetly.com" };

コンソールログ(バイオ);

// 上記の呼び出しは以下を返します:
{ firstName: "Oluwatobi", lastName: "Sofela", ウェブサイト: "codesweetly.com" };

実行結果を見る

上記のコードでは、スプレッド演算子を使用して、myName オブジェクトの内容を bio オブジェクトに複製します。

知らせ:

  • スプレッド演算子は反復可能なオブジェクトの値のみをスプレッドできます。
  • オブジェクトは、@@iterator キーを持つプロパティが含まれている場合にのみ反復可能です。
  • Array、TypedArray、String、Map、Set はすべてデフォルトで @@iterator 属性を持っているため、組み込みの反復可能な型です。
  • プロパティ オブジェクトは、デフォルトでは @@iterator 属性がないため、反復不可能な配列型です。
  • プロパティ オブジェクトに @@iterator を追加して、反復可能なオブジェクトにすることができます。

2. スプレッド演算子は同じプロパティを複製しない

スプレッド演算子を使用してオブジェクト A のプロパティをオブジェクト B に複製するとします。オブジェクト B にオブジェクト A と同じプロパティが含まれている場合、オブジェクト B のプロパティによってオブジェクト A のプロパティが上書きされます。つまり、このプロセスでは、オブジェクト A 内のプロパティのうちオブジェクト B 内のプロパティと同じものは複製されません。

次の例を考えてみましょう。

 const myName = { firstName: "Tobi", lastName: "Sofela" };
const bio = { ...myName、firstName: "Oluwatobi"、ウェブサイト: "codesweetly.com" };

コンソールログ(バイオ);

// 上記の呼び出しは以下を返します:
{ firstName: "Oluwatobi", lastName: "Sofela", ウェブサイト: "codesweetly.com" };

実行結果を見る

bio オブジェクトにはすでに firstName プロパティが含まれているため、スプレッド演算子は myName オブジェクトの firstName プロパティの値を bio オブジェクトにコピーしないことに注意してください。

3. スプレッド演算子が非プリミティブを含むオブジェクトでどのように機能するかに注目してください

プリミティブ値のみを含むオブジェクト (または配列) に対してスプレッド演算子を使用すると、JavaScript は元のオブジェクトとコピーされたオブジェクトの間に参照を作成しません。

次のコードを考えてみましょう。

 const myName = ["Sofela", "is", "my"];
const aboutMe = ["Oluwatobi", ...myName, "名前。"];

console.log(aboutMe);

// 上記の呼び出しは以下を返します:
[「オルワトビ」、「ソフェラ」、「は」、「私の」、「名前」。]

実行結果を見る

myName の各要素はプリミティブ値であるため、スプレッド演算子を使用して myName を aboutMe に複製すると、JavaScript は 2 つの配列間に参照を作成しないことに注意してください。したがって、myName 配列に加えられた変更は aboutMe 配列には反映されず、その逆も同様です。

myName 配列に要素を追加してみましょう。

 myName.push("real");

それでは、myNameとaboutMeの値を確認しましょう。

console.log(myName); // ["Sofela", "is", "my", "real"]

console.log(aboutMe); // ["Oluwatobi", "Sofela", "is", "my", "name."]

スプレッド演算子は元の配列とコピーされた配列の間に参照を作成しないため、myName 配列への変更は aboutMe 配列に反映されないことに注意してください。

myName 配列に非プリミティブ項目が含まれている場合はどうなりますか?

myName に非プリミティブ項目が含まれているとします。この場合、スプレッド演算子は、元の配列の非プリミティブ項目と複製された項目の間に参照を作成します。

次の例を見てください。

 const myName = [["Sofela", "is", "my"]];
const aboutMe = ["Oluwatobi", ...myName, "名前。"];

console.log(aboutMe);

// 上記の呼び出しは以下を返します:
[「オルワトビ」、「ソフェラ」、「は」、「私の」]、「名前です。」]

実行結果を見る

ここで、myName 配列には非プリミティブ項目が含まれていることに注意してください。

したがって、スプレッド演算子を使用して myName の内容を aboutMe に複製すると、JavaScript によって 2 つの配列間の参照が作成されます。こうすることで、myName 配列に加えられた変更はすべて aboutMe 配列に反映され、その逆も同様になります。

例として、myName 配列に要素を追加してみましょう。

 myName[0].push("実数");

それでは、myNameとaboutMeの値を確認しましょう。

 console.log(myName); // [["Sofela", "is", "my", "real"]]

console.log(aboutMe); // ["Oluwatobi", ["Sofela", "is", "my", "real"], "name."]

実行結果を見る

スプレッド演算子によって元の配列とコピーされた配列の間に参照が作成されるため、myName 配列への変更が aboutMe 配列に反映されることに注意してください。

別の例:

 const myName = { firstName: "オルワトビ", lastName: "ソフェラ" };
bio を myName に格納します。

myName.firstName = "トビ";

console.log(myName); // { firstName: "Tobi", lastName: "Sofela" }

console.log(bio); // { firstName: "オルワトビ", lastName: "ソフェラ" }

実行結果を見る

上記のコードでは、プリミティブ値のみを含むオブジェクトに対してスプレッド演算子を使用しているため、myName の更新されたコンテンツは bio オブジェクトに反映されません。

myName にはプリミティブ項目のみが含まれているため、開発者はここで myName を浅いオブジェクトと呼ぶことが多いことに注意してください。

別の例:

定数myName = { 
 フルネーム: { ファーストネーム: "オルワトビ", ラストネーム: "ソフェラ" }
};

bio を myName に格納します。

myName.fullName.firstName = "トビ";

console.log(myName); // { fullName: { firstName: "Tobi", lastName: "Sofela" } }

console.log(bio); // { fullName: { firstName: "Tobi", lastName: "Sofela" } }

実行結果を見る

上記のコードでは、非プリミティブ値を含むオブジェクトにスプレッド演算子を使用しているため、myName の更新されたコンテンツが bio オブジェクトに反映されます。

知らせ:

  • ここでは、myName には非プリミティブ項目が含まれているため、これをディープ オブジェクトと呼びます。
  • あるオブジェクトを別のオブジェクトに複製するときに参照が作成されると、浅いコピーが実行されます。たとえば、...myName は、一方のオブジェクトに加えた変更が他方のオブジェクトに反映されるため、myName オブジェクトの浅いコピーを生成します。
  • オブジェクトを別のオブジェクトに複製する場合、参照が作成されていない場合はディープ コピーが実行されます。たとえば、const bio = JSON.parse(JSON.stringify(myName)) を使用すると、myName オブジェクトを bio オブジェクトにディープコピーできます。この方法では、JavaScript は参照を作成せずに myName を bio に複製します。
  • myName または bio のいずれかの fullName サブオブジェクトを新しいオブジェクトに置き換えることで、myName と bio 間の参照を切断できます。たとえば、myName と bio の間のポインターを分割するには、myName.fullName = { firstName: "Tobi", lastName: "Sofela" } を使用します。

結論

この記事では、REST 演算子とスプレッド演算子の違いについて説明し、例を挙げて JavaScript でどのように機能するかを説明します。

これで、JavaScript のスプレッド演算子とレスト演算子の違いに関するこの記事は終了です。JavaScript のスプレッド演算子とレスト演算子の詳細については、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • JS ES6 スプレッド演算子の魔法のような使い方
  • スプレッド演算子のサンプルコードと JavaScript での応用

<<:  CSS3で実装されたダイナミックな星空の背景

>>:  クロスオリジン画像リソース権限(CORS 対応画像)

推薦する

W3C組織はHTML4のスタイルに関する推奨事項を提供しています

これは、W3C 組織が HTML4 に対して提示したスタイル推奨事項です。残念ながら、ブラウザが独自...

CentOS SVN サーバーで複数のプロジェクトを管理する方法

一つの要求一般的に、企業には複数のプロジェクトがあります。SVN サーバーを設定した後は、プロジェク...

MySQL シリーズ 8 MySQL サーバー変数

チュートリアルシリーズMySQL シリーズ: MySQL リレーショナル データベースの基本概念My...

javascript:void(0) の意味と使用例

voidキーワードの紹介まず、void キーワードは JavaScript で非常に重要なキーワード...

IE6 フォントを定義できません: 13px サイズは無効です。IE6 は自動的に大きいフォント ソリューションを表示します。

数日前、Web ページのモジュールを調整していたとき、ページのフォント サイズを 13px に設定し...

JS 正規マッチングの落とし穴の記録

最近、JS の正規表現マッチングの落とし穴を発見したのですが、その時はあまりにも奇妙だったので、何か...

MySQL シリーズ データベース設計 3 つのパラダイム チュートリアルの例

目次1. データベース設計の3つのパラダイムに関する知識の説明1. デザインパラダイムとは何ですか?...

任意の長さの配列を作成または埋めるための JS のヒントの要約

目次序文直接充填方式for ループの push() メソッド配列コンストラクタメソッド配列コンストラ...

mysql8.0.18 で winx64 をインストールするための詳細なチュートリアル (画像とテキスト付き)

MySQLデータベースをダウンロードするには、https://dev.mysql.com/down...

HTMLでアンカーの位置を設定するためのいくつかの一般的な方法

HTML でアンカーの位置を設定する方法はいくつかあるので、ここで紹介します。 1. ID ポジショ...

CentOS 環境で NFS リモート ディレクトリ マウントを使用する手順の紹介

目次1. NFS の概要2. NFS構築1. NFSサーバーの構築2. NFSクライアントの構築3....

高同時実行シナリオにおける nginx 最適化の詳細な説明

日常の運用・保守作業では、nginx サービスが頻繁に使用され、nginx の高同時実行性によって生...

ホストNginx + Docker WordPress Mysqlを設定するための詳細な手順

環境Linux 3.10.0-693.el7.x86_64 Docker バージョン 18.09.0...

mysql バックアップ スクリプト mysqldump の使い方の詳細な説明

この記事では、参考までにMySQLバックアップスクリプトを紹介します。具体的な内容は次のとおりです。...

DockerとDocker-Composeの使用例

Docker は、アプリケーションをより速く配信するのに役立つオープンソースのコンテナ エンジンです...