10. デストラクチャリング
10. デストラクチャリング#
- 10.1. 10.1.1.概要
- 10.1.1. オブジェクトの破棄
- 10.1.2. 配列の破壊
- 10.1.3. 破壊はどこで使用できますか?
- 10.2. 背景:データの構築とデータの抽出
- 10.3. 破壊のためのパターン
- 10.3.1. あなたが必要なものを選ぶ
- 10.4. パターンはどのように値の内臓にアクセスしますか?
- 10.4.1. オブジェクトパターンは値をオブジェクト
- 10.4.2に強制します。 配列パターンはiterablesで動作します
- 10.5. デフォルト値
- 10.5.1.
undefined
はデフォルト値 - 10.5.2をトリガします。 デフォルト値は、オンデマンド
- 10.5.3で計算されます。 デフォルト値は、パターン
- 10.5.4の他の変数を参照できます。 パターンのデフォルト値
- 10.5.5. より複雑なデフォルト値
- 10.5.1.
- 10.6. より多くのオブジェクト破壊機能
- 10.6.1. プロパティ値の省略形
- 10.6.2. 計算されたプロパティキー
- 10.7. より多くの配列破壊機能
- 10.7.1. Elision
- 10.7.2. Rest演算子(
...
)
- 10.8. 変数
- 10.9以上に割り当てることができます。 破壊の落とし穴
- 10.9.1. 中括弧で文を開始しないでください
- 10.10. 破壊の例
- 10.10.1. 破壊は、配列
- 10.10.2を返しました。 破棄が返されたオブジェクト
- 10.10.3. 10.10.4.配列破壊反復可能な値
- 10.10.4. 複数の戻り値
- 10.11. 破壊アルゴリズム
- 10.11.1. アルゴリズム
- 10.11.2. アルゴリズムの適用
10.1 概要#
デストラクチャリングは、オブジェクトや配列に格納されている(ネストされている可能性がある)データから複数の値を抽出する便利な方法です。 これは、データを受信する場所(割り当ての左側など)で使用できます。 値を抽出する方法は、パターンを介して指定されます(例を参照)。
10.1.1オブジェクトの破壊#
オブジェクトの破壊:
破棄は戻り値の処理に役立ちます:
10.1.2 配列の破棄#
配列の破棄(すべての反復可能な値に対して機能します):
破棄は戻り値の処理に役立ちます:
10.1.3 破壊はどこで使用できますか? #
破壊は次の場所で使用できます(私は示すために配列パターンを示しています;オブジェクトパターンも同様に動作します):
また、for-of
ループで破壊することもできます:
10.2 背景:データの構築とデータの抽出#
破壊とは何かを完全に理解するために、まずそのより広い文脈を調べてみましょう。
JavaScriptは、一度に一つのプロパティをデータを構築するための操作を持っています:
同じ構文を使用してデータを抽出できます。 再び、一度に一つのプロパティ:
さらに、オブジェクトリテラルを介して複数のプロパティを同時に構築する構文があります:
ES6以前は、データを抽出するための対応するメカニズムはありませんでした。 これは、オブジェクトパターンを介してオブジェクトから複数のプロパティを抽出することができます。 たとえば、割り当ての左側には、次のように表示されます:
パターンを介して配列を破壊することもできます:
10.破壊のための3つのパターン#
破壊には以下の二つの当事者が関与しています:
- Destructuring source:destructuredされるデータ。 たとえば、分割代入の右側です。
- Destructuring target:destructuringに使用されるパターン。 たとえば、分割代入の左側です。
破壊対象は三つのパターンのいずれかです:
- 割り当て対象。 例えば:
x
- 代入対象は、通常は変数です。 しかし、destructuring assignmentでは、後で説明するように、より多くのオプションがあります。
- オブジェクトパターン。 例えば:
{ first: "pattern", last: "pattern" }
- オブジェクトパターンの部分はプロパティであり、プロパティ値は再びパターンです(再帰的に)。
- 配列パターン。 例えば:
- 配列パターンの部分は要素であり、要素は再びパターンです(再帰的に)。
つまり、パターンを任意に深く入れ子にすることができます:
10.3.1必要なものを選ぶ#
オブジェクトを破壊する場合は、興味のあるプロパティだけを言及します:
配列を破壊する場合は、接頭辞のみを抽出することを選択できます:
10.4 パターンはどのように値の内臓にアクセスしますか? #
割り当てpattern = someValue
では、pattern
はsomeValue
内のものにどのようにアクセスしますか?
10.4.1オブジェクトパターンは値をオブジェクトに強制します#
オブジェクトパターンは、プロパティにアクセスする前にソースをオブジェクトに強制 つまり、プリミティブ値で動作することを意味します:
10.4.1.1 値#
オブジェクトの破壊に失敗した場合、オブジェクトへの強制はObject()
ではなく、内部操作ToObject()
を介して実行されます。 2つの操作は、undefined
とnull
を別々に処理します。
Object()
プリミティブ値をラッパーオブジェクトに変換し、オブジェクトをそのまま残します:
It also converts undefined
and null
to empty objects:
In contrast, ToObject()
throws a TypeError
if it encounters undefined
or null
. Therefore, the following destructurings fail, even before destructuring accesses any properties:
その結果、空のオブジェクトパターン{}
を使用して、値がオブジェクトに強制可能かどうかを確認できます。 我々が見てきたように、undefined
とnull
だけがそうではありません:
JavaScriptでは文の先頭が中括弧であってはならないため、式の周りの括弧が必要です(詳細は後述します)。
10.4.2配列パターンはiterablesで動作します#
配列破壊は、イテレータを使用してソースの要素を取得します。 したがって、反復可能な任意の値を配列破壊することができます。 反復可能な値の例を見てみましょう。
文字列は反復可能です:
文字列に対するイテレータは、コード単位(”JavaScript文字”、16ビット)ではなく、コードポイント(”Unicode文字”、21ビット)を返すことを忘れないでください。 (Unicodeの詳細については、”第24章”の章を参照してください。 UnicodeとJavaScript”で”Javascriptを話す”。)例えば:
インデックスを介してセットの要素にアクセスすることはできませんが、イテレータを介してアクセスできます。 したがって、配列の破壊は集合に対して機能します:
Set
イテレータは、要素が挿入された順序で常に返されるため、前の破棄の結果は常に同じになります。
10.4.2.1値の配列破壊に失敗しました#
キーがSymbol.iterator
でオブジェクトを返すメソッドがある場合、値は反復可能です。 Array-destructuringは、破棄される値が反復可能でない場合、TypeError
をスローします:
つまり、空の配列パターンを使用して、値が反復可能かどうかを確認できます。
TypeError
は、iterableの要素にアクセスする前であってもスローされます。は、値がiterableかどうかを:
10.5 デフォルト値#
デフォルト値はパターンのオプション機能です。 ソースに何も見つからない場合は、フォールバックを提供します。 部分(オブジェクトプロパティまたは配列要素)がソース内に一致しない場合、それは次の要素と照合されます:
- デフォルト値(指定されている場合; それは任意です)
-
undefined
(それ以外の場合)
例を見てみましょう。 次の分割では、インデックス0の要素は右側に一致しません。 したがって、破壊はx
と3を一致させることによって継続され、x
は3に設定されます。
オブジェクトパターンで既定値を使用することもできます:
10.5.1 undefined
トリガのデフォルト値#
デフォルト値は、パーツに一致があり、その一致がundefined
の場合にも使用されます:
この動作の理論的根拠については、次の章の”パラメータのデフォルト値”のセクションで説明します。
10.5.2デフォルト値はオンデマンドで計算されます#
デフォルト値自体は必要なときにのみ計算されます。 言い換えれば、この破壊:
と等価である。:
あなたが使用する場合、あなたはそれを観察することができますconsole.log()
:
In the second destructuring, the default value is not triggered and log()
is not called.
10.5.3 Default values can refer to other variables in the pattern #
A default value can refer to any variable, including other variables in the same pattern:
しかし、注文事項: 変数x
とy
は左から右に宣言され、宣言の前にアクセスされた場合はReferenceError
を生成します:
10.5.4 パターンのデフォルト値#
これまでのところ、変数のデフォルト値のみを見てきましたが、それらをパターンに関連付けることもできます:
これはどういう意味ですか? デフォルト値のルールを思い出してください:パーツにソースに一致するものがない場合、デストラクチャリングはデフォルト値で続行されます。
インデックス0の要素には一致しないため、破壊が続行されます:
パターン{ prop: x }
を変数に置き換えると、このように動作する理由をより簡単に確認できますpattern
:
10.5.5 より複雑なデフォルト値#
パターンのデフォルト値をさらに調べてみましょう。 次の例では、デフォルト値{ prop: 123 }
を使用してx
に値を割り当てます:
インデックス0の配列要素は右側に一致しないため、次のように分割が続行され、x
が123に設定されます。
ただし、右側にインデックス0の要素がある場合、デフォルト値はトリガーされないため、x
にはこの方法で値が割り当てられません。
この場合、破壊は次のように続きます:
したがって、オブジェクトまたはプロパティのいずれかが欠落している場合にx
を123にする場合は、x
自体にデフォルト値を指定する必要があります:
ここでは、右辺がであるか
であるかにかかわらず、破壊は次のように続きます。
10.6 その他のオブジェクト分割機能#
10.6.1プロパティ値の省略形#
プロパティ値の省略形は、オブジェクトリテラルの機能です: プロパティ値がプロパティキーと同じ名前の変数である場合は、キーを省略できます。 これは、あまりにも、破壊のために動作します:
また、プロパティ値の省略形を既定値と組み合わせることもできます:
10.6.2 計算されたプロパティキー#
計算されたプロパティキーは、破壊にも機能する別のオブジェクトリテラル機能です。 プロパティのキーは、角括弧に入れた場合、式を介して指定できます:
計算されたプロパティキーを使用すると、キーがシンボルであるプロパティを:
10.7 その他の配列破壊機能#
10.7.1Elision#
Elisionでは、配列”穴”の構文を使用して、破壊中に要素をスキップできます:
10.7.2 Rest演算子(...
) #
rest演算子を使用すると、iterableの残りの要素を配列に抽出できます。 この演算子が配列パターン内で使用されている場合は、最後に来る必要があります:
演算子が要素を見つけることができない場合は、空の配列に対してオペランドと一致します。 つまり、undefined
またはnull
は生成されません。 例えば:
rest演算子のオペランドは変数である必要はなく、パターンも使用できます:
rest演算子は、次の破壊をトリガーします:
10.8変数以外にも割り当てることができます#
分割を介して割り当てる場合、各割り当てターゲットは通常の割り当ての左側で許可されているすべてのものにすることができます。
たとえば、プロパティへの参照(obj.prop
):
または配列要素への参照(arr
):
rest演算子(...
)を使用して、オブジェクトプロパティと配列要素に割り当てることもできます:
変数を宣言したり、分割を介してパラメータを定義したりする場合は、単純な識別子を使用する必要があります。
10.9デストラクチャリングの落とし穴#
デストラクチャを使用するときに注意すべきことが二つあります:
- 中括弧で文を開始することはできません。
- デストラクチャ中に、変数を宣言するか、変数に割り当てることができますが、両方はできません。
次の二つのセクションには詳細が含まれています。
10.9.1中括弧で文を開始しないでください#
コードブロックは中括弧で始まるため、文は中括弧で始まってはいけません。 これは、代入でオブジェクトの破壊を使用する場合には残念です:
回避策は、完全な式を括弧内に入れることです:
次の構文は機能しません:
let
、var
、const
では、中括弧が問題を引き起こすことはありません:
10.10個の破壊の例#
いくつかの小さな例から始めましょう。
for-of
ループは破壊をサポートしています:
分割を使用して値を交換することができます。 これは、エンジンが最適化できるため、配列が作成されないようにするものです。
分割を使用して配列を分割することができます:
10.10.1 返された配列の破棄#
組み込みのJavaScript操作の中には、配列を返すものがあります。 破壊はそれらを処理するのに役立ちます:
グループのみに関心がある場合(完全な一致ではなく、all
)、elisionを使用してインデックスの配列要素をスキップすることができます0:
exec()
正規表現が一致しない場合は、null
を返します。 残念ながら、デフォルト値でnull
を処理することはできないため、この場合はOr演算子(||
)を使用する必要があります:
Array.prototype.split()
配列を返します。 したがって、配列ではなく要素に興味がある場合は、破壊が便利です:
10.10.2 destructuring returned objects#
Destructuringは、関数またはメソッドによって返されるオブジェクトからデータを抽出するのにも役立ちます。 たとえば、イテレータメソッドnext()
は、done
とvalue
の2つのプロパティを持つオブジェクトを返します。 次のコードは、Iteratoriter
を介してArrayarr
のすべての要素をログに記録します。 A行目では破壊が使用されます。
10.10.3 Array-destructuring iterable values#
Array-destructuringは任意の反復可能な値で動作します。 それは時折便利です:
10.10.4 複数の戻り値#
複数の戻り値の有用性を確認するには、関数p
がtrue
を返す配列a
の最初の要素を検索する関数findElement(a, p)
を実装しましょう。 問題は、findElement()
は何を返すべきかです。 時には、要素自体に、時にはそのインデックスに、時には両方に興味があることもあります。 次の実装では、両方を返します。
この関数は、配列メソッドentries()
を介してarray
のすべての要素を反復処理し、ペア(行A)に対する反復可能な値を返します。 ペアの部分は、破壊を介してアクセスされます。
findElement()
:
ECMAScript6のいくつかの機能により、より簡潔なコードを記述することができました。コールバックは矢印関数です。戻り値はプロパティ値の省略形を持つオブジェクトパターンを介して破棄されます。
index
とelement
もプロパティキーを参照しているため、それらを言及する順序は問題ではありません。 我々はそれらを交換することができ、何も変更されません:
我々は正常にインデックスと要素の両方を必要とする場合を処理しました。 私たちがそのうちの1つだけに興味がある場合はどうなりますか? ECMAScript6のおかげで、私たちの実装もそれを処理できることがわかりました。 また、単一の戻り値を持つ関数と比較した構文上のオーバーヘッドは最小限です。
毎回、必要な1つのプロパティの値のみを抽出します。
10.11destructuring algorithm#
このセクションでは、再帰的なパターンマッチングアルゴリズムとして、別の角度からdestructuringを見ています。
最後に、アルゴリズムを使用して、次の2つの関数宣言の違いを説明します。
10.11.1 アルゴリズム#
分割代入は次のようになります:
pattern
を使用してvalue
からデータを抽出します。 ここでは、関数型プログラミングでパターンマッチング(略してマッチング)として知られているそのためのアルゴリズムについて説明します。 このアルゴリズムは、pattern
とvalue
に一致し、そうしている間に変数に代入する分割代入のための演算子←
(“match against”)を指定します:
このアルゴリズムは、←
演算子の両方のオペランドを分解する再帰規則によって指定されます。 宣言的表記法には慣れるまでに時間がかかるかもしれませんが、アルゴリズムの仕様をより簡潔にします。 各ルールには2つの部分があります:
- 先頭(最初の行)には、ルールをトリガーする条件が記述されています。
- 本文(残りの行)は、ルールがトリガーされた場合の処理を記述します。
例を見てみましょう:
- (2c)
{key: "pattern", "properties"} ← obj
- (2e)
{} ← obj
(プロパティが残っていません)
ルール(2c)では、headは、少なくとも一つのプロパティとゼロ以上の残りのプロパティを持つオブジェクトパターンがある場合、このルールが実行されるこ そのパターンは値obj
と照合されます。 このルールの効果は、プロパティ値パターンがobj.key
と照合され、残りのプロパティがobj
と照合されて実行が続行されることです。
ルール(2e)では、headは、空のオブジェクトパターン{}
が値obj
と一致した場合、このルールが実行されることを意味します。 その後、何もすることはありません。
アルゴリズムが呼び出されるたびに、ルールは上から下にチェックされ、適用可能な最初のルールのみが実行されます。
私は分割代入のアルゴリズムのみを示しています。 変数宣言の破棄とパラメータ定義の破棄も同様に機能します。
私は高度な機能をカバーしていません(計算されたプロパティキー、プロパティ値の省略形; オブジェクトのプロパティと配列要素を代入対象として)。 基本だけ。
10.11.1.1パターン#
パターンは次のいずれかです:
- 変数:
x
- オブジェクトパターン:
{"properties"}
- 配列パターン:
以下の各セクションでは、これら3つのケースのいずれかについて説明します。
以下の三つのセクションでは、これら三つのケースの処理方法を指定しています。 各セクションには、1つ以上の番号付きルールが含まれています。
10.11.1.2変数#
- (1)
x ← value
(undefined
を含むお絵かき掲示板null
)
10.11.1.3 オブジェクトパターン#
- (2a)
{"properties"} ← undefined
- (2b)
{"properties"} ← null
- (2c)
{key: "pattern", "properties"} ← obj
- (2次元)
{key: "pattern" = default_value, "properties"} ← obj
- (2e)
{} ← obj
(プロパティが残っていません)
10.11.1.4 配列パターン#
配列パターンとiterable。 配列分割のアルゴリズムは、配列パターンとiterableから始まります:
- (3a)
← non_iterable
assert(!isIterable(non_iterable))
- (3b)
← iterable
assert(isIterable(iterable))
ヘルパー関数:
配列要素とイテレータ。 このアルゴリズムは、パターンの要素(矢印の左側)と、iterableから取得したイテレータ(矢印の右側)に続きます。
- (3c)
"pattern", "elements" ← iterator
- (3d)
"pattern" = default_value, "elements" ← iterator
- (3e)
, "elements" ← iterator
(穴、省略)
- (3f)
..."pattern" ← iterator
(常に最後の部分!)
- (3g)
← iterator
(要素が残っていません)
ヘルパー関数:
10.11.2 アルゴリズム#
をECMAScript6で適用すると、呼び出し元がオブジェクトリテラルを使用し、呼び出し先が破壊を使用する場合、名前付きパラメータをシミュ このシミュレーションについては、パラメータ処理の章で詳しく説明します。 次のコードは例を示しています。functionmove1()
には、x
とx
という2つの名前付きパラメーターがありますy
:
行Aには3つのデフォルト値があります:
- 最初の2つのデフォルト値を使用すると、
x
とy
を省略できます。 - 3番目のデフォルト値を使用すると、(最後の行のように)パラメータなしで
move1()
を呼び出すことができます。
しかし、なぜ前のコードスニペットのようにパラメータを定義するのですか? なぜ次のように–また、完全に合法的なES6コードですか?
なぜmove1()
が正しいのかを確認するために、2つの例で両方の関数を使用しましょう。 それを行う前に、パラメータの渡しがマッチングによってどのように説明できるかを見てみましょう。
10.11.2.1背景:マッチング#
を介してパラメータを渡す関数呼び出しの場合、仮パラメータ(関数定義内)は、実際のパラメータ(関数呼び出し内)と照合されます。 例として、次の関数定義と次の関数呼び出しを考えてみましょう。
パラメータa
とb
は、次の破壊と同様に設定されます。
10.11.2.2 を使用してmove2()
#
move2()
の破壊がどのように機能するかを調べてみましょう。
例1. move2()
:
左側の単一の配列要素は右側に一致しないため、{x,y}
は右側のデータではなくデフォルト値と一致します(ルール3b、3d):
左側にはプロパティ値の省略形が含まれています。:
この分割により、次の二つの割り当てが行われます(ルール2c, 1):
例2. 次の破壊につながる関数呼び出しmove2({z:3})
を調べてみましょう:
右側のインデックス0に配列要素があります。 したがって、デフォルト値は無視され、次のステップは(rule3d)です。:
これにより、x
とy
の両方がundefined
に設定されますが、これは私たちが望むものではありません。
10.11.2.3move1()
#
move1()
を試してみましょう。
1: move1()
右側のインデックス0に配列要素がなく、デフォルト値(ルール3d)を使用します):
左側にはプロパティ値の省略形が含まれています。:
プロパティx
もプロパティy
も右側に一致しません。 したがって、デフォルト値が使用され、次に次の破壊が実行されます(ルール2d):
これにより、次の割り当て(ルール)が行われます1):
例2: move1({z:3})
配列パターンの最初の要素には右側に一致があり、その一致は破壊を続行するために使用されます(ルール3d):
例1のように、右側にプロパティx
とy
がなく、既定値が使用されます:
10.11.2.4 結論#
この例では、デフォルト値がパターン部分(オブジェクトプロパティまたは配列要素)の機能であることを示しています。 部品に一致がない場合、またはundefined
と一致する場合は、デフォルト値が使用されます。 つまり、パターンは代わりにデフォルト値と照合されます。