When I try to merge two objects using the spread operator conditionally, it works when the condition is true
or false
:
let condition = false;
let obj1 = { key1: 'value1'}
let obj2 = {
key2: 'value2',
...(condition && obj1),
};
// obj2 = {key2: 'value2'};
When I try to use the same logic with Arrays, it only works when the condition is true
:
let condition = true;
let arr1 = ['value1'];
let arr2 = ['value2', ...(condition && arr1)];
// arr2 = ['value2', 'value1']
If the condition is false
an error is thrown:
let condition = false;
let arr1 = ['value1'];
let arr2 = ['value2', ...(condition && arr1)];
// Error
Why is the behaviour different between Array
and Object
?
false
is not spreadable.You need a spreadable object (the one where
Symbol.iterator
is implemented) which returns nothing, if spreaded.You could use an empty array as default value. This works even if
arr
is falsy.When you spread into an array, you call the
Symbol.iterator
method on the object.&&
evaluates to the first falsey value (or the last truthy value, if all are truthy), soresults in
But
false
does not have aSymbol.iterator
method.You could use the conditional operator instead, and spread an empty array if the condition is false:
(This works because the empty array does have the
Symbol.iterator
method)Object spread is completely different: it copies own enumerable properties from a provided object onto a new object.
false
does not have any own enumerable properties, so nothing gets copied.This is a specification difference between the spread syntax for object literals and for array literals.
MDN briefly mentions it here -- I highlight:
The difference comes from the EcmaScript 2018 specification:
Concerning object spread syntax, see 12.2.6.8 Runtime Semantics: PropertyDefinitionEvaluation:
CopyDataProperties(object, fromValue, excludedNames)
where the fromValue is wrapped to an object withToObject
, and therefore becomes iterable, even if fromValue is a primitive value likefalse
. Therefore{...false}
is valid EcmaScript.Concerning array spread syntax, see 12.2.5.2 Runtime Semantics: ArrayAccumulation:
GetValue(spreadRef)
which does not do the above mentioned wrapping. And so the subsequent call toGetIterator
will trigger an error on a primitive value, as it is not iterable. Therefore[...false]
is invalid EcmaScript.