[英]Add elements inside Array conditionally in JavaScript
When I try to merge two objects using the spread operator conditionally, it works when the condition is true
or false
:当我尝试有条件地使用扩展运算符合并两个对象时,它在条件为
true
或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
:当我尝试对数组使用相同的逻辑时,它仅在条件为
true
时才有效:
let condition = true;
let arr1 = ['value1'];
let arr2 = ['value2', ...(condition && arr1)];
// arr2 = ['value2', 'value1']
If the condition is false
an error is thrown:如果条件为
false
,则抛出错误:
let condition = false; let arr1 = ['value1']; let arr2 = ['value2', ...(condition && arr1)]; // Error
Why is the behaviour different between Array
and Object
?为什么
Array
和Object
之间的行为不同?
When you spread into an array , you call the Symbol.iterator
method on the object.当你扩展到一个数组时,你在对象上调用
Symbol.iterator
方法。 &&
evaluates to the first falsey value (or the last truthy value, if all are truthy), so &&
计算为第一个假值(或最后一个真值,如果全部都是真值),所以
let arr2 = ['value2', ...(condition && arr)];
results in结果是
let arr2 = ['value2', ...(false)];
But false
does not have a Symbol.iterator
method.但是
false
没有Symbol.iterator
方法。
You could use the conditional operator instead, and spread an empty array if the condition is false:您可以改用条件运算符,如果条件为假,则扩展一个空数组:
let condition = false; let arr1 = ['value1']; let arr2 = ['value2', ...(condition ? arr1 : [])]; console.log(arr2);
(This works because the empty array does have the Symbol.iterator
method) (这是有效的,因为空数组确实有
Symbol.iterator
方法)
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. false
没有任何自己的可枚举属性,因此不会复制任何内容。
false
is not spreadable. false
不可传播。
You need a spreadable object (the one where Symbol.iterator
is implemented) which returns nothing, if spreaded.您需要一个可展开的对象(实现
Symbol.iterator
对象),如果展开, Symbol.iterator
返回任何内容。
You could use an empty array as default value.您可以使用空数组作为默认值。 This works even if
arr
is falsy .即使
arr
为假,这也有效。
let condition = false; let arr1 = ['value1']; let arr2 = ['value2', ...(condition && arr || [])]; console.log(arr2);
This is a specification difference between the spread syntax for object literals and for array literals.这是对象字面量和数组字面量的展开语法之间的规范差异。
MDN briefly mentions it here -- I highlight: MDN 在这里简要提到它——我强调:
Spread syntax ( other than in the case of spread properties ) can be applied only to iterable objects
传播语法(传播属性除外)只能应用于可迭代对象
The difference comes from the EcmaScript 2018 specification:区别来自 EcmaScript 2018 规范:
Concerning object spread syntax, see 12.2.6.8 Runtime Semantics: PropertyDefinitionEvaluation :关于对象传播语法,请参见12.2.6.8 运行时语义:PropertyDefinitionEvaluation :
CopyDataProperties(object, fromValue, excludedNames)
where the fromValue is wrapped to an object with ToObject
, and therefore becomes iterable, even if fromValue is a primitive value like false
.CopyDataProperties(object, fromValue, excludedNames)
其中fromValue缠绕到与对象ToObject
,因此变得可迭代,即使fromValue就像是一个原始值false
。 Therefore {...false}
is valid EcmaScript.{...false}
是有效的EcmaScript。 Concerning array spread syntax, see 12.2.5.2 Runtime Semantics: ArrayAccumulation :关于数组展开语法,请参见12.2.5.2 运行时语义: ArrayAccumulation :
GetValue(spreadRef)
which does not do the above mentioned wrapping.GetValue(spreadRef)
而不会进行上述包装。 And so the subsequent call to GetIterator
will trigger an error on a primitive value, as it is not iterable.GetIterator
的后续调用将在原始值上触发错误,因为它不可迭代。 Therefore [...false]
is invalid EcmaScript.[...false]
是无效的EcmaScript。Example with objects:对象示例:
const lessonMenuItems = [
...(true
? [
{
value: 'post',
},
]
: []),
{
value: 'assign',
},
]
Result:结果:
lessonMenuItems = [
{
value: 'post',
},
{
value: 'assign',
},
]
You can use a ternary operator (? :) and put an empty array as the false您可以使用三元运算符(? :) 并将一个空数组作为 false
let condition = false; let arr1 = ['value1']; let arr2 = ['value2', ...(condition ? arr1 : [])]; console.log(arr2);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.