3.4 Applying the algorithm
In JavaScript, named parameters are simulated via objects: The caller uses an object literal and the callee uses destructuring. This simulation is explained in detail in “JavaScript for impatient programmers”. The following code shows an example: function move1()
has two named parameters, x
and y
:
function move1({x=0, y=0} = {}) { // (A)
return [x, y];
}
assert.deepEqual(
move1({x: 3, y: 8}), [3, 8]);
assert.deepEqual(
move1({x: 3}), [3, 0]);
assert.deepEqual(
move1({}), [0, 0]);
assert.deepEqual(
move1(), [0, 0]);
There are three default values in line A:
- The first two default values allow us to omit
x
andy
. - The third default value allows us to call
move1()
without parameters (as in the last line).
But why would we define the parameters as in the previous code snippet? Why not as follows?
function move2({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
To see why move1()
is correct, we are going to use both functions in two examples. Before we do that, let’s see how the passing of parameters can be explained via matching.
3.4.1 Background: passing parameters via matching
For function calls, formal parameters (inside function definitions) are matched against actual parameters (inside function calls). As an example, take the following function definition and the following function call.
function func(a=0, b=0) { ··· }
func(1, 2);
The parameters a
and b
are set up similarly to the following destructuring.
[a=0, b=0] ← [1, 2]
3.4.2 Using move2()
Let’s examine how destructuring works for move2()
.
Example 1. The function call move2()
leads to this destructuring:
[{x, y} = { x: 0, y: 0 }] ← []
The single Array element on the left-hand side does not have a match on the right-hand side, which is why {x,y}
is matched against the default value and not against data from the right-hand side (rules 3b, 3d):
{x, y} ← { x: 0, y: 0 }
The left-hand side contains property value shorthands. It is an abbreviation for:
{x: x, y: y} ← { x: 0, y: 0 }
This destructuring leads to the following two assignments (rules 2c, 1):
x = 0;
y = 0;
This is what we wanted. However, in the next example, we are not as lucky.
Example 2. Let’s examine the function call move2({z: 3})
which leads to the following destructuring:
[{x, y} = { x: 0, y: 0 }] ← [{z: 3}]
There is an Array element at index 0 on the right-hand side. Therefore, the default value is ignored and the next step is (rule 3d):
{x, y} ← { z: 3 }
That leads to both x
and y
being set to undefined
, which is not what we want. The problem is that {x,y}
is not matched against the default value, anymore, but against {z:3}
.
3.4.3 Using move1()
Let’s try move1()
.
Example 1: move1()
[{x=0, y=0} = {}] ← []
We don’t have an Array element at index 0 on the right-hand side and use the default value (rule 3d):
{x=0, y=0} ← {}
The left-hand side contains property value shorthands, which means that this destructuring is equivalent to:
{x: x=0, y: y=0} ← {}
Neither property x
nor property y
have a match on the right-hand side. Therefore, the default values are used and the following destructurings are performed next (rule 2d):
x ← 0
y ← 0
That leads to the following assignments (rule 1):
x = 0
y = 0
Here, we get what we want. Let’s see if our luck holds with the next example.
Example 2: move1({z: 3})
[{x=0, y=0} = {}] ← [{z: 3}]
The first element of the Array pattern has a match on the right-hand side and that match is used to continue destructuring (rule 3d):
{x=0, y=0} ← {z: 3}
Like in example 1, there are no properties x
and y
on the right-hand side and the default values are used:
x = 0
y = 0
It works as desired! This time, the pattern with x
and y
being matched against {z:3}
is not a problem, because they have their own local default values.
3.4.4 Conclusion: Default values are a feature of pattern parts
The examples demonstrate that default values are a feature of pattern parts (object properties or Array elements). If a part has no match or is matched against undefined
then the default value is used. That is, the pattern is matched against the default value, instead.