3.2 The pattern matching algorithm
3.2.1 Patterns
A pattern is either:
- A variable:
x
- An object pattern:
{«properties»}
- An Array pattern:
[«elements»]
The next three sections specify rules for handling these three cases in matching expressions.
3.2.2 Rules for variable
x ← value
(includingundefined
andnull
)
x = value
3.2.3 Rules for object patterns
(2a)
{«properties»} ← undefined
(illegal value)throw new TypeError();
(2b)
{«properties»} ← null
(illegal value)throw new TypeError();
(2c)
{key: «pattern», «properties»} ← obj
«pattern» ← obj.key
{«properties»} ← obj
(2d)
{key: «pattern» = default_value, «properties»} ← obj
const tmp = obj.key;
if (tmp !== undefined) {
«pattern» ← tmp
} else {
«pattern» ← default_value
}
{«properties»} ← obj
(2e)
{} ← obj
(no properties left)// We are finished
Rules 2a and 2b deal with illegal values. Rules 2c–2e loop over the properties of the pattern. In rule 2d, we can see that a default value provides an alternative to match against if there is no matching property in obj
.
3.2.4 Rules for Array patterns
Array pattern and iterable. The algorithm for Array destructuring starts with an Array pattern and an iterable:
(3a)
[«elements»] ← non_iterable
(illegal value)if (!isIterable(non_iterable))
throw new TypeError();
(3b)
[«elements»] ← iterable
if (isIterable(iterable))
const iterator = iterable[Symbol.iterator]();
«elements» ← iterator
Helper function:
function isIterable(value) {
return (value !== null
&& typeof value === 'object'
&& typeof value[Symbol.iterator] === 'function');
}
Array elements and iterator. The algorithm continues with:
- The elements of the pattern (left-hand side of the arrow)
- The iterator that was obtained from the iterable (right-hand side of the arrow)
These are the rules:
(3c)
«pattern», «elements» ← iterator
«pattern» ← getNext(iterator) // undefined after last item
«elements» ← iterator
(3d)
«pattern» = default_value, «elements» ← iterator
const tmp = getNext(iterator); // undefined after last item
if (tmp !== undefined) {
«pattern» ← tmp
} else {
«pattern» ← default_value
}
«elements» ← iterator
(3e)
, «elements» ← iterator
(hole, elision)getNext(iterator); // skip
«elements» ← iterator
(3f)
...«pattern» ← iterator
(always last part!)const tmp = [];
for (const elem of iterator) {
tmp.push(elem);
}
«pattern» ← tmp
(3g)
← iterator
(no elements left)// We are finished
Helper function:
function getNext(iterator) {
const {done,value} = iterator.next();
return (done ? undefined : value);
}
An iterator being finished is similar to missing properties in objects.