JavaScript で最もよく使用される 2 つのデータ構造は、 Object
とArray
です。
オブジェクトを使用すると、データ項目をキーごとに格納する単一のエンティティを作成できます。
配列を使用すると、データ項目を順序付きリストに収集できます。
ただし、これらを関数に渡す場合、そのすべてが必要なわけではありません。関数には特定の要素またはプロパティのみが必要な場合があります。
構造化代入は、配列やオブジェクトを多数の変数に「解凍」できるようにする特別な構文です。場合によっては、その方が便利なこともあります。
分割は、多くのパラメータやデフォルト値などを持つ複雑な関数でもうまく機能します。もうすぐそれがわかります。
以下は、配列が変数に分解される例です。
// 名前と姓を含む配列があります let arr = ["ジョン", "スミス"] // 代入の構造化 // firstName = arr[0] を設定します // 姓 = arr[1] let [名、姓] = arr; アラート(名); // ジョン アラート(姓); // スミス
これで、配列メンバーの代わりに変数を操作できるようになりました。
これは、 split
または他の配列を返すメソッドと組み合わせると見栄えがよくなります。
let [名、姓] = "ジョン スミス".split(' '); アラート(名); // ジョン アラート(姓); // スミス
ご覧のとおり、構文は単純です。ただし、いくつかの奇妙な詳細があります。よりよく理解するために、さらに例を見てみましょう。
「破壊」とは「破壊的」という意味ではありません。
項目を変数にコピーすることで「構造化」するため、これは「構造化代入」と呼ばれます。ただし、配列自体は変更されません。
これは単に短く書いた方法です:
// let [名、姓] = arr; firstName = arr[0]; にします。 姓 = arr[1] とします。
カンマを使用した要素を無視する
配列の不要な要素は、追加のカンマを使用して破棄することもできます。
// 2番目の要素は必要ありません let [firstName, , title] = ["ジュリアス"、"カエサル"、"執政官"、"ローマ共和国の"]; アラート(タイトル); // 領事
上記のコードでは、配列の 2 番目の要素がスキップされ、3 番目の要素がtitle
に割り当てられ、残りの配列項目も (変数がないため) スキップされます。
右側の任意の反復可能オブジェクトで動作します
…実際には、配列だけでなく、あらゆる反復可能オブジェクトで使用できます。
[a, b, c] = "abc" とします。 // ["a", "b", "c"] let [1、2、3] = new Set([1, 2, 3]);
これは、内部的には適切な値を反復処理することによって構造化代入が機能するため、機能します。これは、 =
の右側の値に対してfor..of
を呼び出し、値を代入するための一種の構文です。
左側にあるものに割り当てます
左側の「割り当て可能項目」を使用できます。
たとえば、オブジェクトのプロパティは次のようになります。
ユーザー = {} にします。 [ユーザー名、ユーザー名] = "ジョン・スミス".split(' '); アラート(ユーザー名); // ジョン アラート(ユーザー.姓); // スミス
.entries() によるループ
前の章では、Object.entries(obj) メソッドについて説明しました。
これを構造化とともに使用して、オブジェクトのキーと値をループすることができます。
ユーザー = { にします 名前:「ジョン」、 年齢: 30歳 }; // キーと値をループします。 for (let [key, value] of Object.entries(user)) { アラート(`${キー}:${値}`); // 名前:ジョン、年齢:30 }
Map
の同様のコードは反復可能であるため、より単純です。
let user = new Map(); user.set("名前", "ジョン"); user.set("年齢", "30"); // マップは [キー, 値] ペアとして反復され、構造化に非常に便利です for (let [キー, 値] のユーザー) { アラート(`${キー}:${値}`); // 名前:ジョン、年齢:30 }
変数を交換するトリック
構造化代入を使用して 2 つの変数の値を交換するためのよく知られたトリックがあります。
ゲスト = "ジェーン" にします。 管理者 = "ピート"; // 値を交換しましょう: guest=Pete、admin=Jane にします [ゲスト、管理者] = [管理者、ゲスト]; アラート(`${ゲスト} ${管理者}`); // ピート・ジェーン (正常に交換されました!)
ここでは、2 つの変数の一時配列を作成し、それを交換された順序ですぐに構造解除します。
この方法で 3 つ以上の変数を交換できます。
通常、配列が左側のリストより長い場合、「余分な」項目は省略されます。
たとえば、ここでは 2 つの項目のみが取得され、残りは無視されます。
let [name1, name2] = ["ジュリアス"、"カエサル"、"執政官"、"ローマ共和国の"]; アラート(名前1); // ユリウス アラート(名前2); // カエサル // それ以上の項目はどこにも割り当てられません
以下の内容もすべて収集したい場合は、3 つのドット"..."
を使用して「残り」を取得するパラメーターをもう 1 つ追加できます。
let [name1, name2, ...rest] = ["ジュリアス", "カエサル", "執政官", "ローマ共和国の"]; // 残りは 3 番目から始まる項目の配列です アラート(残り[0]); // 領事 アラート(残り[1]); // ローマ共和国の アラート(残りの長さ); // 2
rest
の値は、残りの配列要素の配列です。
rest
の代わりに他の変数名を使用できますが、変数名の前に 3 つのドットがあり、構造化代入の最後に置かれるようにしてください。
let [name1, name2, ...titles] = ["ジュリアス"、"カエサル"、"執政官"、"ローマ共和国の"]; // 現在のタイトル = ["執政官", "ローマ共和国の"]
配列が左側の変数のリストより短い場合、エラーは発生しません。存在しない値は未定義とみなされます。
[名、姓] = []; にします。 アラート(名); // 未定義 アラート(姓); // 未定義
不足している値を「デフォルト」値で置き換えたい場合は、 =
使用してそれを指定できます。
// デフォルト値 let [名前 = "ゲスト"、姓 = "匿名"] = ["ジュリアス"]; アラート(名前); // ジュリアス (配列から) アラート(姓); // 匿名 (デフォルトが使用されます)
デフォルト値は、より複雑な式や関数呼び出しにすることもできます。値が指定されていない場合にのみ評価されます。
たとえば、ここでは 2 つのデフォルトに対してprompt
関数を使用します。
// 姓のプロンプトのみを実行します let [名前 = プロンプト('名前?')、姓 = プロンプト('姓?')] = ["ジュリアス"]; アラート(名前); // ジュリアス (配列から) アラート(姓); // どのようなプロンプトが表示されても
注意: prompt
欠落値 ( surname
) に対してのみ実行されます。
分割代入はオブジェクトでも機能します。
基本的な構文は次のとおりです。
{var1, var2} = {var1:…, var2:…} とします。
変数に分割したい既存のオブジェクトが右側にあるはずです。左側には、対応するプロパティのオブジェクトのような「パターン」が含まれています。最も単純なケースでは、これは{...}
内の変数名のリストです。
例えば:
let オプション = { タイトル: 「メニュー」、 幅: 100、 高さ: 200 }; {タイトル、幅、高さ} = オプション; アラート(タイトル); // メニュー アラート(幅); // 100 アラート(高さ); // 200
プロパティoptions.title
、 options.width
、およびoptions.height
は、対応する変数に割り当てられます。
順序は関係ありません。これも機能します:
// let {...} の順序を変更しました let {高さ、幅、タイトル} = { タイトル: "メニュー"、高さ: 200、幅: 100 }
左側のパターンはより複雑で、プロパティと変数の間のマッピングを指定する場合があります。
プロパティを別の名前の変数に割り当てたい場合、たとえば、 options.width
w
という名前の変数に代入する場合は、コロンを使用して変数名を設定できます。
let オプション = { タイトル: 「メニュー」、 幅: 100、 高さ: 200 }; // { ソースプロパティ: ターゲット変数 } {幅: w、高さ: h、タイトル} = オプション; // 幅 -> w // 高さ -> h // タイトル -> タイトル アラート(タイトル); // メニュー アラート(w); // 100 アラート(h); // 200
コロンは「何を:どこに行くか」を示します。上の例では、プロパティのwidth
w
に、プロパティのheight
はh
に、 title
は同じ名前に割り当てられます。
欠落している可能性があるプロパティについては、次のように"="
使用してデフォルト値を設定できます。
let オプション = { タイトル:「メニュー」 }; let {幅 = 100、高さ = 200、タイトル} = オプション; アラート(タイトル); // メニュー アラート(幅); // 100 アラート(高さ); // 200
配列や関数パラメータと同様に、デフォルト値には任意の式や関数呼び出しを指定できます。値が指定されていない場合は評価されます。
以下のコードでは、 prompt
width
を要求しますが、 title
要求しません。
let オプション = { タイトル:「メニュー」 }; let {width = プロンプト("width?"), title = プロンプト("title?")} = オプション; アラート(タイトル); // メニュー アラート(幅); // (プロンプトの結果が何であれ)
コロンと等号の両方を組み合わせることもできます。
let オプション = { タイトル:「メニュー」 }; let {幅: w = 100、高さ: h = 200、タイトル} = オプション; アラート(タイトル); // メニュー アラート(w); // 100 アラート(h); // 200
多くのプロパティを持つ複雑なオブジェクトがある場合、必要なものだけを抽出できます。
let オプション = { タイトル: 「メニュー」、 幅: 100、 高さ: 200 }; // タイトルのみを変数として抽出します let { title } = オプション; アラート(タイトル); // メニュー
オブジェクトに変数よりも多くのプロパティがある場合はどうなるでしょうか?いくつか取ってから、どこかに「休息」を割り当てることはできますか?
配列の場合と同様に、残りのパターンを使用できます。一部の古いブラウザ (IE、ポリフィルには Babel を使用) ではサポートされていませんが、最新のブラウザでは動作します。
次のようになります。
let オプション = { タイトル: 「メニュー」、 高さ: 200、 幅: 100 }; // title = title という名前のプロパティ //rest = 残りのプロパティを含むオブジェクト let {title, ...rest} = オプション; // 現在、title="メニュー"、rest={高さ: 200、幅: 100} アラート(残りの高さ); // 200 アラート(残りの幅); // 100
let
がない場合はガッチャ
上記の例では、変数は代入内で宣言されています: let {…} = {…}
。もちろん、 let
使わずに既存の変数を使用することもできます。しかし、落とし穴があります。
これは機能しません:
タイトル、幅、高さを設定します。 // この行のエラー {タイトル、幅、高さ} = {タイトル: "メニュー"、幅: 200、高さ: 100};
問題は、JavaScript が (別の式内ではなく) メイン コード フロー内で{...}
をコード ブロックとして扱うことです。このようなコード ブロックは、次のようにステートメントをグループ化するために使用できます。
{ // コードブロック let message = "こんにちは"; // ... アラート(メッセージ); }
したがって、ここでは JavaScript はコード ブロックがあると想定しているため、エラーが発生します。代わりに、破壊が必要です。
JavaScript にコード ブロックではないことを示すには、式を括弧(...)
で囲みます。
タイトル、幅、高さを設定します。 // もういいよ ({タイトル, 幅, 高さ} = {タイトル: "メニュー", 幅: 200, 高さ: 100}); アラート(タイトル); // メニュー
オブジェクトまたは配列に他のネストされたオブジェクトや配列が含まれている場合は、より複雑な左側のパターンを使用して、より深い部分を抽出できます。
以下のコードではoptions
プロパティsize
に別のオブジェクトがあり、プロパティitems
に配列が含まれています。代入の左側のパターンは、値を抽出するための同じ構造を持っています。
let オプション = { サイズ: { 幅: 100、 高さ: 200 }、 アイテム: ["ケーキ"、"ドーナツ"]、 追加: 本当 }; // わかりやすくするために代入を複数行に分割して構造化しています させて { size: { // ここにサイズを入力します 幅、 身長 }、 items: [item1, item2], // ここに項目を割り当てます title = "Menu" // オブジェクトには存在しません (デフォルト値が使用されます) } = オプション; アラート(タイトル); // メニュー アラート(幅); // 100 アラート(高さ); // 200 アラート(項目1); // ケーキ アラート(項目2); // ドーナツ
左側の部分にないextra
を除く、 options
オブジェクトのすべてのプロパティは、対応する変数に割り当てられます。
最後に、デフォルト値からwidth
、 height
、 item1
、 item2
、 title
取得します。
size
とitems
の変数はなく、代わりにそれらの内容を取得することに注意してください。
関数に多くのパラメーターがあり、そのほとんどがオプションである場合があります。これは特にユーザー インターフェイスに当てはまります。メニューを作成する関数を想像してください。幅、高さ、タイトル、項目リストなどが含まれる場合があります。
このような関数を記述する間違った方法は次のとおりです。
function showMenu(title = "無題", width = 200, height = 100, items = []) { // ... }
実生活では、引数の順序をどうやって覚えるかが問題になります。通常、特にコードが十分に文書化されている場合、IDE は私たちを助けようとしますが、それでも… もう 1 つの問題は、ほとんどのパラメーターがデフォルトで問題ない場合に関数を呼び出す方法です。
このような?
// 未定義の場合はデフォルト値で問題ありません showMenu("マイメニュー", 未定義, 未定義, ["項目 1", "項目 2"])
それは醜いです。さらに多くのパラメーターを扱うと、判読できなくなります。
破壊が助けになります!
パラメーターをオブジェクトとして渡すと、関数はそれらをすぐに変数に構造化します。
// オブジェクトを関数に渡します let オプション = { タイトル: 「私のメニュー」、 項目: ["項目 1"、"項目 2"] }; // ...そしてすぐに変数に展開します function showMenu({title = "無題", width = 200, height = 100, items = []}) { // タイトル、項目 – オプションから取得、 // 幅、高さ - デフォルトが使用されます アラート( `${タイトル} ${幅} ${高さ}` ); // マイメニュー 200 100 アラート(アイテム); // アイテム1、アイテム2 } showMenu(オプション);
ネストされたオブジェクトとコロン マッピングを使用して、より複雑な構造化を使用することもできます。
let オプション = { タイトル: 「私のメニュー」、 項目: ["項目 1"、"項目 2"] }; 関数 showMenu({ title = "無題", width: w = 100, // 幅は w になります height: h = 200, // 高さは h になります items: [item1, item2] // items 最初の要素は item1 に、2 番目の要素は item2 に移動します }){ アラート( `${title} ${w} ${h}` ); // マイメニュー 100 200 アラート( item1 ); // アイテム1 アラート( item2 ); // 項目2 } showMenu(オプション);
完全な構文は、構造化代入の場合と同じです。
関数({ incomingProperty: varName = defaultValue ... })
次に、パラメーターのオブジェクトの場合、プロパティincomingProperty
の変数varName
が存在し、デフォルトではdefaultValue
が設定されます。
このような分割では、 showMenu()
に引数があることが前提となっていることに注意してください。デフォルトですべての値が必要な場合は、空のオブジェクトを指定する必要があります。
showMenu({}); // OK、すべての値はデフォルトです showMenu(); // これではエラーが発生します
これは、 {}
パラメータのオブジェクト全体のデフォルト値にすることで修正できます。
function showMenu({ title = "メニュー", width = 100, height = 200 } = {}) { アラート( `${タイトル} ${幅} ${高さ}` ); } showMenu(); // メニュー 100 200
上記のコードでは、引数オブジェクト全体がデフォルトで{}
であるため、常に構造化すべきものが存在します。
代入を分割すると、オブジェクトまたは配列を多くの変数に即座にマッピングできます。
完全なオブジェクト構文:
let {prop : varName = defaultValue, ...rest} = オブジェクト
これは、プロパティprop
変数varName
に入れる必要があり、そのようなプロパティが存在しない場合はdefault
値を使用する必要があることを意味します。
マッピングのないオブジェクト プロパティはrest
オブジェクトにコピーされます。
完全な配列構文:
let [item1 = defaultValue, item2, ...rest] = 配列
最初の項目はitem1
に移動します。 2 番目はitem2
に入り、残りはすべて配列rest
となります。
ネストされた配列/オブジェクトからデータを抽出することは可能ですが、そのためには左側が右側と同じ構造を持つ必要があります。
重要度: 5
オブジェクトがあります:
ユーザー = { にします 名前:「ジョン」、 年数: 30 };
次のような構造化代入を記述します。
name
プロパティを変数name
に取り込みます。
years
プロパティを変数age
に取り込みます。
isAdmin
プロパティを変数isAdmin
に設定します (そのようなプロパティがない場合は false)
割り当て後の値の例を次に示します。
let user = { 名前: "ジョン"、年齢: 30 }; // 左側にコードを追加します。 // ... = ユーザー アラート( 名前 ); // ジョン アラート(年齢); // 30 アラート( isAdmin ); // 間違い
ユーザー = { にします 名前:「ジョン」、 年数: 30 }; {名前、年: 年齢、isAdmin = false} = ユーザー; アラート( 名前 ); // ジョン アラート(年齢); // 30 アラート( isAdmin ); // 間違い
重要度: 5
salaries
オブジェクトがあります。
給与 = { とします 「ジョン」: 100、 「ピート」: 300、 「メアリー」:250 };
最高額の給与を支払った人の名前を返す関数topSalary(salaries)
を作成します。
salaries
が空の場合は、 null
を返す必要があります。
高額報酬をもらった人が複数いる場合は、そのうちの誰かを返します。
PS Object.entries
と構造化を使用して、キーと値のペアを反復処理します。
テストを含むサンドボックスを開きます。
関数 topSalary(給与) { maxSalary = 0 とします。 maxName = null にします。 for(const [名前, 給与] of Object.entries(salaries)) { if (maxSalary < 給与) { maxSalary = 給与; maxName = 名前; } } maxName を返します。 }
サンドボックス内のテストを含むソリューションを開きます。