简体   繁体   English

在 JavaScript 中有条件地在 Array 中添加元素

[英]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 :当我尝试有条件地使用扩展运算符合并两个对象时,它在条件为truefalse时起作用:

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 ?为什么ArrayObject之间的行为不同?

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

    • It calls 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

    • It merely calls 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM