undefined
はデフォルト値をトリガーします...
)デストラクチャリングは、(入れ子になった可能性のある)オブジェクトと配列に格納されたデータから複数の値を抽出する便利な方法です。データを受け取る場所(代入の左辺など)で使用できます。値の抽出方法はパターンで指定します(例を参照)。
オブジェクトのデストラクチャリング
const
obj
=
{
first
:
'Jane'
,
last
:
'Doe'
};
const
{
first
:
f
,
last
:
l
}
=
obj
;
// f = 'Jane'; l = 'Doe'
// {prop} is short for {prop: prop}
const
{
first
,
last
}
=
obj
;
// first = 'Jane'; last = 'Doe'
デストラクチャリングは戻り値の処理に役立ちます
const
obj
=
{
foo
:
123
};
const
{
writable
,
configurable
}
=
Object
.
getOwnPropertyDescriptor
(
obj
,
'foo'
);
console
.
log
(
writable
,
configurable
);
// true true
配列デストラクチャリング(すべてのイテラブル値で動作します)
const
iterable
=
[
'a'
,
'b'
];
const
[
x
,
y
]
=
iterable
;
// x = 'a'; y = 'b'
デストラクチャリングは戻り値の処理に役立ちます
const
[
all
,
year
,
month
,
day
]
=
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.
exec
(
'2999-12-31'
);
デストラクチャリングは次の場所で使用できます(配列パターンを示していますが、オブジェクトパターンも同様に機能します)。
// Variable declarations:
const
[
x
]
=
[
'a'
];
let
[
x
]
=
[
'a'
];
var
[
x
]
=
[
'a'
];
// Assignments:
[
x
]
=
[
'a'
];
// Parameter definitions:
function
f
([
x
])
{
···
}
f
([
'a'
]);
for-of
ループでもデストラクチャリングできます。
const
arr
=
[
'a'
,
'b'
];
for
(
const
[
index
,
element
]
of
arr
.
entries
())
{
console
.
log
(
index
,
element
);
}
// Output:
// 0 a
// 1 b
デストラクチャリングが何かを完全に理解するには、まずその広いコンテキストを調べましょう。
JavaScriptには、一度に1つのプロパティでデータを構築する操作があります。
const
obj
=
{};
obj
.
first
=
'Jane'
;
obj
.
last
=
'Doe'
;
同じ構文を使用してデータを抽出できます。これも、一度に1つのプロパティです。
const
f
=
obj
.
first
;
const
l
=
obj
.
last
;
さらに、オブジェクトリテラルを介して、複数のプロパティを同時に構築する構文があります。
const
obj
=
{
first
:
'Jane'
,
last
:
'Doe'
};
ES6以前は、データ抽出に対応するメカニズムがありませんでした。それがデストラクチャリングです。オブジェクトから複数のプロパティをオブジェクトパターンを使用して抽出できます。たとえば、代入の左辺で。
const
{
first
:
f
,
last
:
l
}
=
obj
;
パターンを使用して配列をデストラクチャリングすることもできます。
const
[
x
,
y
]
=
[
'a'
,
'b'
];
// x = 'a'; y = 'b'
デストラクチャリングには次の2つの当事者が関係しています。
デストラクチャリングターゲットは、次の3つのパターンのいずれかです。
x
{ first: «パターン», last: «パターン» }
[ «パターン», «パターン» ]
つまり、パターンを任意の深さで入れ子にすることができます。
const
obj
=
{
a
:
[{
foo
:
123
,
bar
:
'abc'
},
{}],
b
:
true
};
const
{
a
:
[{
foo
:
f
}]
}
=
obj
;
// f = 123
オブジェクトをデストラクチャリングする場合、関心のあるプロパティのみを指定します。
const
{
x
:
x
}
=
{
x
:
7
,
y
:
3
};
// x = 7
配列をデストラクチャリングする場合は、プレフィックスのみを抽出するように選択できます。
const
[
x
,
y
]
=
[
'a'
,
'b'
,
'c'
];
// x='a'; y='b';
代入pattern = someValue
では、pattern
はどのようにsomeValue
の中身をアクセスしますか?
オブジェクトパターンは、プロパティにアクセスする前に、デストラクチャリングソースをオブジェクトに強制変換します。つまり、プリミティブ値でも動作します。
const
{
length
:
len
}
=
'abc'
;
// len = 3
const
{
toString
:
s
}
=
123
;
// s = Number.prototype.toString
オブジェクトへの強制変換はObject()
ではなく、内部操作ToObject()
を介して実行されます。これら2つの操作は、undefined
とnull
を異なる方法で処理します。
Object()
はプリミティブ値をラッパーオブジェクトに変換し、オブジェクトはそのままにします。
> typeof Object('abc')
'object'
> var obj = {};
> Object(obj) === obj
true
また、undefined
とnull
を空のオブジェクトに変換します。
> Object(undefined)
{}
> Object(null)
{}
対照的に、ToObject()
はundefined
またはnull
に遭遇するとTypeError
をスローします。したがって、次のデストラクチャリングは、デストラクチャリングがプロパティにアクセスする前でも失敗します。
const
{
prop
:
x
}
=
undefined
;
// TypeError
const
{
prop
:
y
}
=
null
;
// TypeError
結果として、空のオブジェクトパターン{}
を使用して、値がオブジェクトに変換可能かどうかを確認できます。前述のように、undefined
とnull
のみが変換できません。
({}
=
[
true
,
false
]);
// OK, Arrays are coercible to objects
({}
=
'abc'
);
// OK, strings are coercible to objects
({}
=
undefined
);
// TypeError
({}
=
null
);
// TypeError
式を囲む括弧は、JavaScriptではステートメントを中括弧で始めることができないため必要です(詳細は後で説明します)。
配列デストラクチャリングはイテレータを使用してソースの要素にアクセスします。したがって、イテラブルな値であれば、配列デストラクチャリングを使用できます。イテラブル値の例を見てみましょう。
文字列はイテラブルです。
const
[
x
,...
y
]
=
'abc'
;
// x='a'; y=['b', 'c']
文字列のイテレータは、コードユニット(「JavaScript文字」、16ビット)ではなく、コードポイント(「Unicode文字」、21ビット)を返すことに注意してください。(Unicodeの詳細については、「Speaking JavaScript」の「第24章 UnicodeとJavaScript」を参照してください)。たとえば、
const
[
x
,
y
,
z
]
=
'a\uD83D\uDCA9c'
;
// x='a'; y='\uD83D\uDCA9'; z='c'
インデックスを介してSetの要素にアクセスすることはできませんが、イテレータを介してアクセスできます。したがって、配列デストラクチャリングはSetでも機能します。
const
[
x
,
y
]
=
new
Set
([
'a'
,
'b'
]);
// x='a'; y='b’;
Set
イテレータは、常に挿入された順序で要素を返し、そのため、前のデストラクチャリングの結果は常に同じです。
値がイテラブルであるとは、キーがSymbol.iterator
であり、オブジェクトを返すメソッドを持つことを意味します。配列デストラクチャリングは、デストラクチャリングする値がイテラブルでない場合、TypeError
をスローします。
let
x
;
[
x
]
=
[
true
,
false
];
// OK, Arrays are iterable
[
x
]
=
'abc'
;
// OK, strings are iterable
[
x
]
=
{
*
[
Symbol
.
iterator
]()
{
yield
1
}
};
// OK, iterable
[
x
]
=
{};
// TypeError, empty objects are not iterable
[
x
]
=
undefined
;
// TypeError, not iterable
[
x
]
=
null
;
// TypeError, not iterable
TypeError
は、イテラブルの要素にアクセスする前でもスローされます。つまり、空の配列パターン[]
を使用して、値がイテラブルかどうかを確認できます。
[]
=
{};
// TypeError, empty objects are not iterable
[]
=
undefined
;
// TypeError, not iterable
[]
=
null
;
// TypeError, not iterable
デフォルト値は、パターンのオプション機能です。ソースで見つからない場合のフォールバックを提供します。ある部分(オブジェクトのプロパティまたは配列の要素)にソースに一致するものがない場合、それは次のものと照合されます。
undefined
(それ以外の場合は)例を見てみましょう。次のデストラクチャリングでは、インデックス0の要素には右辺に一致するものがないため、デストラクチャリングはx
と3の照合を続行し、x
が3に設定されます。
const
[
x
=
3
,
y
]
=
[];
// x = 3; y = undefined
オブジェクトパターンでもデフォルト値を使用できます。
const
{
foo
:
x
=
3
,
bar
:
y
}
=
{};
// x = 3; y = undefined
undefined
はデフォルト値をトリガーします 部分に一致するものがあり、その一致がundefined
の場合も、デフォルト値が使用されます。
const
[
x
=
1
]
=
[
undefined
];
// x = 1
const
{
prop
:
y
=
2
}
=
{
prop
:
undefined
};
// y = 2
この動作の理由は、次の章のパラメータのデフォルト値に関するセクションで説明されています。
デフォルト値自体は、必要になった場合にのみ計算されます。言い換えれば、このデストラクチャリング
const
{
prop
:
y
=
someFunc
()}
=
someValue
;
は次のものと同等です。
let
y
;
if
(
someValue
.
prop
===
undefined
)
{
y
=
someFunc
();
}
else
{
y
=
someValue
.
prop
;
}
console.log()
を使用すると、確認できます。
> function log(x) { console.log(x); return 'YES' }
> const [a=log('hello')] = [];
> a
'YES'
> const [b=log('hello')] = [123];
> b
123
2番目のデストラクチャリングでは、デフォルト値はトリガーされず、log()
は呼び出されません。
デフォルト値は、同じパターン内の他の変数を含む、任意の変数を参照できます。
const
[
x
=
3
,
y
=
x
]
=
[];
// x=3; y=3
const
[
x
=
3
,
y
=
x
]
=
[
7
];
// x=7; y=7
const
[
x
=
3
,
y
=
x
]
=
[
7
,
2
];
// x=7; y=2
ただし、順序が重要です。変数x
とy
は左から右に宣言され、宣言前にアクセスされるとReferenceError
が発生します。
const
[
x
=
y
,
y
=
3
]
=
[];
// ReferenceError
これまでは変数に対するデフォルト値しか見ていませんでしたが、パターンにも関連付けることができます。
const
[{
prop
:
x
}
=
{}]
=
[];
これはどういう意味ですか?デフォルト値の規則を思い出してください。ある部分にソースに一致するものがない場合、デストラクチャリングはデフォルト値で続行されます。
インデックス0の要素に一致するものがないため、デストラクチャリングは次のようになります。
const
{
prop
:
x
}
=
{};
// x = undefined
パターン{ prop: x }
を変数pattern
に置き換えると、動作がより分かりやすくなります。
const
[
pattern
=
{}]
=
[];
パターンに対するデフォルト値をさらに詳しく見てみましょう。次の例では、デフォルト値{ prop: 123 }
を介してx
に値を代入します。
const
[{
prop
:
x
}
=
{
prop
:
123
}]
=
[];
インデックス 0 の配列要素に右辺に相当するものが無い場合、デストラクチャリングは次のように継続し、x
は 123 に設定されます。
const
{
prop
:
x
}
=
{
prop
:
123
};
// x = 123
しかし、右辺にインデックス 0 の要素が存在する場合、この方法では x
に値が割り当てられません。これは、デフォルト値がトリガーされないためです。
const
[{
prop
:
x
}
=
{
prop
:
123
}]
=
[{}];
この場合、デストラクチャリングは次のように継続します。
const
{
prop
:
x
}
=
{};
// x = undefined
したがって、オブジェクトまたはプロパティのいずれかが欠けている場合に x
を 123 にしたい場合は、x
自体にデフォルト値を指定する必要があります。
const
[{
prop
:
x
=
123
}
=
{}]
=
[{}];
ここでは、右辺が [{}]
か []
かに関係なく、デストラクチャリングは次のように継続します。
const
{
prop
:
x
=
123
}
=
{};
// x = 123
プロパティ値の省略記法は、オブジェクトリテラルの機能です。プロパティ値がプロパティキーと同じ名前の変数である場合、キーを省略できます。これはデストラクチャリングにも適用されます。
const
{
x
,
y
}
=
{
x
:
11
,
y
:
8
};
// x = 11; y = 8
// Same as:
const
{
x
:
x
,
y
:
y
}
=
{
x
:
11
,
y
:
8
};
プロパティ値の省略記法とデフォルト値を組み合わせることもできます。
const
{
x
,
y
=
1
}
=
{};
// x = undefined; y = 1
計算されたプロパティキーは、デストラクチャリングにも適用される別のオブジェクトリテラル機能です。角括弧で囲むことで、式を使用してプロパティのキーを指定できます。
const
FOO
=
'foo'
;
const
{
[
FOO
]
:
f
}
=
{
foo
:
123
};
// f = 123
計算されたプロパティキーを使用すると、キーがシンボルであるプロパティをデストラクチャリングできます。
// Create and destructure a property whose key is a symbol
const
KEY
=
Symbol
();
const
obj
=
{
[
KEY
]
:
'abc'
};
const
{
[
KEY
]
:
x
}
=
obj
;
// x = 'abc'
// Extract Array.prototype[Symbol.iterator]
const
{
[
Symbol
.
iterator
]
:
func
}
=
[];
console
.
log
(
typeof
func
);
// function
省略記法を使用すると、配列の「穴」の構文を使用して、デストラクチャリング中に要素をスキップできます。
const
[,,
x
,
y
]
=
[
'a'
,
'b'
,
'c'
,
'd'
];
// x = 'c'; y = 'd'
...
) レスト演算子を使用すると、反復可能な要素の残りの要素を配列に抽出できます。この演算子を配列パターン内で使用する場合、最後に配置する必要があります。
const
[
x
,
...
y
]
=
[
'a'
,
'b'
,
'c'
];
// x='a'; y=['b', 'c']
演算子が要素を見つけられない場合、空の配列に対してオペランドを照合します。つまり、undefined
や null
を生成することはありません。例:
const
[
x
,
y
,
...
z
]
=
[
'a'
];
// x='a'; y=undefined; z=[]
レスト演算子のオペランドは変数である必要はなく、パターンも使用できます。
const
[
x
,
...[
y
,
z
]]
=
[
'a'
,
'b'
,
'c'
];
// x = 'a'; y = 'b'; z = 'c'
レスト演算子は、次のデストラクチャリングをトリガーします。
[
y
,
z
]
=
[
'b'
,
'c'
]
デストラクチャリングで代入する場合、各代入ターゲットは、通常の代入の左辺で許可されるすべてのものになります。
たとえば、プロパティへの参照 (obj.prop
)
const
obj
=
{};
({
foo
:
obj
.
prop
}
=
{
foo
:
123
});
console
.
log
(
obj
);
// {prop:123}
または、配列要素への参照 (arr[0]
)
const
arr
=
[];
({
bar
:
arr
[
0
]
}
=
{
bar
:
true
});
console
.
log
(
arr
);
// [true]
レスト演算子 (...
) を使用して、オブジェクトのプロパティと配列の要素にも代入できます。
const
obj
=
{};
[
first
,
...
obj
.
prop
]
=
[
'a'
,
'b'
,
'c'
];
// first = 'a'; obj.prop = ['b', 'c']
デストラクチャリングで変数を宣言したり、パラメーターを定義したりする場合は、単純な識別子を使用する必要があります。オブジェクトのプロパティや配列の要素を参照することはできません。
デストラクチャリングを使用する際には、2つの点に注意する必要があります。
次の2つのセクションでは、詳細を説明します。
コードブロックは中括弧で始まるため、文は中括弧で始めることはできません。これは、代入でオブジェクトデストラクチャリングを使用する場合に問題になります。
{
a
,
b
}
=
someObject
;
// SyntaxError
回避策として、完全な式を括弧で囲みます。
({
a
,
b
}
=
someObject
);
// OK
次の構文は機能しません。
({
a
,
b
})
=
someObject
;
// SyntaxError
let
、var
、const
を使用する場合、中括弧は問題になりません。
const
{
a
,
b
}
=
someObject
;
// OK
いくつかの小さな例から始めましょう。
for-of
ループはデストラクチャリングをサポートしています。
const
map
=
new
Map
().
set
(
false
,
'no'
).
set
(
true
,
'yes'
);
for
(
const
[
key
,
value
]
of
map
)
{
console
.
log
(
key
+
' is '
+
value
);
}
デストラクチャリングを使用して値を交換できます。これは、エンジンが最適化できるものであり、配列が作成されないようにできます。
[
a
,
b
]
=
[
b
,
a
];
デストラクチャリングを使用して配列を分割できます。
const
[
first
,
...
rest
]
=
[
'a'
,
'b'
,
'c'
];
// first = 'a'; rest = ['b', 'c']
一部の組み込みJavaScript操作は配列を返します。デストラクチャリングはそれらを処理するのに役立ちます。
const
[
all
,
year
,
month
,
day
]
=
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.
exec
(
'2999-12-31'
);
グループのみに関心があり(完全一致であるall
には関心がない場合)、省略記法を使用してインデックス0の配列要素をスキップできます。
const
[,
year
,
month
,
day
]
=
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.
exec
(
'2999-12-31'
);
正規表現が一致しない場合、exec()
は null
を返します。残念ながら、デフォルト値で null
を処理することはできないため、この場合はOR演算子 (||
) を使用する必要があります。
const
[,
year
,
month
,
day
]
=
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.
exec
(
someStr
)
||
[];
Array.prototype.split()
は配列を返します。したがって、配列ではなく要素に関心がある場合は、デストラクチャリングが役立ちます。
const
cells
=
'Jane\tDoe\tCTO'
const
[
firstName
,
lastName
,
title
]
=
cells
.
split
(
'\t'
);
console
.
log
(
firstName
,
lastName
,
title
);
デストラクチャリングは、関数またはメソッドによって返されるオブジェクトからデータを取り出すのにも役立ちます。たとえば、イテレーターメソッドnext()
は、done
とvalue
の2つのプロパティを持つオブジェクトを返します。次のコードは、イテレーターiter
を使用して配列arr
のすべての要素をログ出力します。デストラクチャリングはA行で使用されています。
const
arr
=
[
'a'
,
'b'
];
const
iter
=
arr
[
Symbol
.
iterator
]();
while
(
true
)
{
const
{
done
,
value
}
=
iter
.
next
();
// (A)
if
(
done
)
break
;
console
.
log
(
value
);
}
配列デストラクチャリングは、あらゆる反復可能な値で動作します。これは時々役立ちます。
const
[
x
,
y
]
=
new
Set
().
add
(
'a'
).
add
(
'b'
);
// x = 'a'; y = 'b'
const
[
a
,
b
]
=
'foo'
;
// a = 'f'; b = 'o'
複数の戻り値の有用性を見るために、関数p
がtrue
を返す配列a
の最初の要素を検索する関数findElement(a, p)
を実装してみましょう。問題は、findElement()
は何を返すべきかということです。要素自体に関心を持つ場合もあれば、そのインデックスに関心を持つ場合もあれば、両方に関心を持つ場合もあります。次の実装は両方返します。
function
findElement
(
array
,
predicate
)
{
for
(
const
[
index
,
element
]
of
array
.
entries
())
{
// (A)
if
(
predicate
(
element
,
index
,
array
))
{
// We found an element:
return
{
element
,
index
};
// Same as (property value shorthands):
// { element: element, index: index }
}
}
// We couldn’t find anything; return failure values:
return
{
element
:
undefined
,
index
:
-
1
};
}
この関数は、[index,element]
ペアを反復処理する配列メソッドentries()
を使用して、配列array
のすべての要素を反復処理します(A行)。ペアの部分はデストラクチャリングを使用してアクセスされます。
findElement()
を使用してみましょう。
const
arr
=
[
7
,
8
,
6
];
const
{
element
,
index
}
=
findElement
(
arr
,
x
=>
x
%
2
===
0
);
// element = 8, index = 1
いくつかのECMAScript 6機能により、より簡潔なコードを書くことができました。コールバックはアロー関数であり、戻り値はプロパティ値の省略記法を持つオブジェクトパターンを使用してデストラクチャリングされます。
index
とelement
もプロパティキーを参照しているため、それらを言及する順序は関係ありません。それらを交換しても何も変わりません。
const
{
index
,
element
}
=
findElement
(
···
);
インデックスと要素の両方に対応することができました。一方のみに関心がある場合はどうでしょうか?ECMAScript 6のおかげで、実装でも対応できます。そして、単一の戻り値を持つ関数と比較した構文上のオーバーヘッドは最小限です。
const
a
=
[
7
,
8
,
6
];
const
{
element
}
=
findElement
(
a
,
x
=>
x
%
2
===
0
);
// element = 8
const
{
index
}
=
findElement
(
a
,
x
=>
x
%
2
===
0
);
// index = 1
毎回、必要な1つのプロパティの値のみを抽出します。
このセクションでは、再帰的なパターンマッチングアルゴリズムとして、異なる角度からデストラクチャリングを見ていきます。
最後に、このアルゴリズムを使用して、次の2つの関数宣言の違いを説明します。
function
move
({
x
=
0
,
y
=
0
}
=
{})
{
···
}
function
move
({
x
,
y
}
=
{
x
:
0
,
y
:
0
})
{
···
}
デストラクチャリング代入は次のようになります。
«
pattern
»
=
«
value
»
pattern
を使用してvalue
からデータを取り出したいと考えています。これを行うためのアルゴリズムを説明します。これは関数型プログラミングではパターンマッチング(略してマッチング)として知られています。このアルゴリズムは、pattern
をvalue
に照合し、その過程で変数に代入するデストラクチャリング代入のための演算子←
(「〜に照合」)を指定します。
«
pattern
»
←
«
value
»
このアルゴリズムは、←
演算子の両方のオペランドを分解する再帰的なルールで指定されています。宣言的な表記には慣れる必要があるかもしれませんが、アルゴリズムの仕様をより簡潔にします。各ルールには2つの部分があります。
例を見てみましょう。
{key: «pattern», «properties»} ← obj
«
pattern
»
←
obj
.
key
{
«
properties
»
}
←
obj
{} ← obj
(残りのプロパティなし)
// Nothing to do
ルール(2c)では、ヘッダーは、少なくとも1つのプロパティと0個以上の残りのプロパティを持つオブジェクトパターンが存在する場合に、このルールが実行されることを意味します。そのパターンは値obj
に照合されます。このルールの効果は、プロパティ値のパターンがobj.key
に照合され、残りのプロパティがobj
に照合されることを続行することです。
ルール(2e)では、ヘッダーは、空のオブジェクトパターン{}
が値obj
に照合される場合にこのルールが実行されることを意味します。その後、行うべきことはありません。
アルゴリズムが呼び出されるたびに、ルールは上から下にチェックされ、適用可能な最初のルールのみが実行されます。
デストラクチャリング代入のアルゴリズムのみを示します。デストラクチャリング変数宣言とデストラクチャリングパラメーター定義は同様に機能します。
高度な機能(計算されたプロパティキー、プロパティ値の省略記法、代入ターゲットとしてのオブジェクトプロパティと配列要素)についても扱いません。基本事項のみです。
パターンは次のいずれかです。
x
{«properties»}
[«elements»]
以下の各セクションでは、これらの3つのケースのそれぞれについて説明します。
以下の3つのセクションでは、これらの3つのケースの処理方法を指定します。各セクションには、1つ以上の番号付きルールが含まれています。
x ← value
(undefined
とnull
を含む)
x
=
value
{«properties»} ← undefined
throw
new
TypeError
();
{«properties»} ← null
throw
new
TypeError
();
{key: «pattern», «properties»} ← obj
«
pattern
»
←
obj
.
key
{
«
properties
»
}
←
obj
{key: «pattern» = default_value, «properties»} ← obj
const
tmp
=
obj
.
key
;
if
(
tmp
!==
undefined
)
{
«
pattern
»
←
tmp
}
else
{
«
pattern
»
←
default_value
}
{
«
properties
»
}
←
obj
{} ← obj
(残りのプロパティなし)
// Nothing to do
配列パターンとイテラブル。配列デストラクチャリングのアルゴリズムは、配列パターンとイテラブルから始まります。
[«elements»] ← non_iterable
assert(!isIterable(non_iterable))
throw
new
TypeError
();
[«elements»] ← iterable
assert(isIterable(iterable))
const
iterator
=
iterable
[
Symbol
.
iterator
]();
«
elements
»
←
iterator
ヘルパー関数
function
isIterable
(
value
)
{
return
(
value
!==
null
&&
typeof
value
===
'object'
&&
typeof
value
[
Symbol
.
iterator
]
===
'function'
);
}
配列要素とイテレータ。アルゴリズムは、パターンの要素(矢印の左側)と、イテラブルから取得されたイテレータ(矢印の右側)を使用して続行されます。
«pattern», «elements» ← iterator
«
pattern
»
←
getNext
(
iterator
)
// undefined after last item
«
elements
»
←
iterator
«pattern» = default_value, «elements» ← iterator
const
tmp
=
getNext
(
iterator
);
// undefined after last item
if
(
tmp
!==
undefined
)
{
«
pattern
»
←
tmp
}
else
{
«
pattern
»
←
default_value
}
«
elements
»
←
iterator
, «elements» ← iterator
(穴、省略)
getNext
(
iterator
);
// skip
«
elements
»
←
iterator
...«pattern» ← iterator
(常に最後の部分!)
const
tmp
=
[];
for
(
const
elem
of
iterator
)
{
tmp
.
push
(
elem
);
}
«
pattern
»
←
tmp
← iterator
(要素が残っていない)
// Nothing to do
ヘルパー関数
function
getNext
(
iterator
)
{
const
{
done
,
value
}
=
iterator
.
next
();
return
(
done
?
undefined
:
value
);
}
ECMAScript 6では、呼び出し元がオブジェクトリテラルを使用し、呼び出し先がデストラクチャリングを使用する場合、名前付きパラメータをシミュレートできます。このシミュレーションについては、パラメータ処理に関する章で詳細に説明します。次のコードは例を示しています。関数move1()
には、x
とy
という2つの名前付きパラメータがあります。
function
move1
({
x
=
0
,
y
=
0
}
=
{})
{
// (A)
return
[
x
,
y
];
}
move1
({
x
:
3
,
y
:
8
});
// [3, 8]
move1
({
x
:
3
});
// [3, 0]
move1
({});
// [0, 0]
move1
();
// [0, 0]
行Aには3つのデフォルト値があります。
x
とy
を省略できます。move1()
を呼び出すことができます(最後の行のように)。しかし、なぜ前のコードスニペットのようにパラメータを定義するのでしょうか?次のようにも完全に合法的なES6コードとして記述できるのに、なぜでしょうか?
function
move2
({
x
,
y
}
=
{
x
:
0
,
y
:
0
})
{
return
[
x
,
y
];
}
move1()
が正しい理由を確認するために、2つの例で両方の関数を使用してみましょう。その前に、パラメータの渡し方をマッチングで説明する方法を見てみましょう。
関数呼び出しでは、仮パラメータ(関数定義内)は実パラメータ(関数呼び出し内)と照合されます。例として、次の関数定義と関数呼び出しを考えてみましょう。
function
func
(
a
=
0
,
b
=
0
)
{
···
}
func
(
1
,
2
);
パラメータa
とb
は、次のデストラクチャリングと同様に設定されます。
[
a
=
0
,
b
=
0
]
←
[
1
,
2
]
move2()
の使用 move2()
でのデストラクチャリングの動作を調べましょう。
例1。move2()
は、次のデストラクチャリングにつながります。
[{
x
,
y
}
=
{
x
:
0
,
y
:
0
}]
←
[]
左辺の単一の配列要素には、右辺に一致するものがないため、{x,y}
はデフォルト値と照合され、右辺のデータとは照合されません(ルール3b、3d)。
{
x
,
y
}
←
{
x
:
0
,
y
:
0
}
左辺にはプロパティ値の省略記法が含まれており、これは次の略記です。
{
x
:
x
,
y
:
y
}
←
{
x
:
0
,
y
:
0
}
このデストラクチャリングにより、次の2つの代入が行われます(ルール2c、1)。
x
=
0
;
y
=
0
;
例2。関数呼び出しmove2({z:3})
を調べましょう。これは次のデストラクチャリングにつながります。
[{
x
,
y
}
=
{
x
:
0
,
y
:
0
}]
←
[{
z
:
3
}]
インデックス0に配列要素があるため、デフォルト値は無視され、次のステップになります(ルール3d)。
{
x
,
y
}
←
{
z
:
3
}
これにより、x
とy
の両方がundefined
に設定されますが、これは私たちが望むものではありません。
move1()
の使用 move1()
を試してみましょう。
例1: move1()
[{
x
=
0
,
y
=
0
}
=
{}]
←
[]
インデックス0に配列要素がないため、デフォルト値を使用します(ルール3d)。
{
x
=
0
,
y
=
0
}
←
{}
左辺にはプロパティ値の省略記法が含まれているため、このデストラクチャリングは次のものと同等です。
{
x
:
x
=
0
,
y
:
y
=
0
}
←
{}
右辺にはプロパティx
もプロパティy
も一致するものがないため、デフォルト値が使用され、次に次のデストラクチャリングが行われます(ルール2d)。
x
←
0
y
←
0
これにより、次の代入が行われます(ルール1)。
x
=
0
y
=
0
例2: move1({z:3})
[{
x
=
0
,
y
=
0
}
=
{}]
←
[{
z
:
3
}]
配列パターンの最初の要素には、右辺に一致するものがあり、その一致を使用してデストラクチャリングを続行します(ルール3d)。
{
x
=
0
,
y
=
0
}
←
{
z
:
3
}
例1と同様に、右辺にプロパティx
とy
がないため、デフォルト値が使用されます。
x
=
0
y
=
0
これらの例は、デフォルト値がパターンの一部(オブジェクトプロパティまたは配列要素)の機能であることを示しています。部分が一致しない場合、またはundefined
と一致する場合、デフォルト値が使用されます。つまり、代わりにパターンがデフォルト値と照合されます。