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

Joã*_*ues 45 javascript ecmascript-6

当我尝试使用传播运算符有条件地合并两个对象时,当条件为true或时,它将起作用false

let condition = false;
let obj1 = { key1: 'value1'}
let obj2 = {
  key2: 'value2',
  ...(condition && obj1),
};

// obj2 = {key2: 'value2'};
Run Code Online (Sandbox Code Playgroud)

当我尝试对数组使用相同的逻辑时,它仅在条件为时才起作用true

let condition = true;
let arr1 = ['value1'];
let arr2 = ['value2', ...(condition && arr1)];

// arr2 = ['value2', 'value1']
Run Code Online (Sandbox Code Playgroud)

如果条件为false错误,则抛出:

let condition = false;
let obj1 = { key1: 'value1'}
let obj2 = {
  key2: 'value2',
  ...(condition && obj1),
};

// obj2 = {key2: 'value2'};
Run Code Online (Sandbox Code Playgroud)

Array和之间的行为为何不同Object

Cer*_*nce 48

当您展开为数组时,可以Symbol.iterator在对象上调用方法。&&计算为第一个假值(如果所有都是真,则为最后一个真值),因此

let arr2 = ['value2', ...(condition && arr)];
Run Code Online (Sandbox Code Playgroud)

结果是

let arr2 = ['value2', ...(false)];
Run Code Online (Sandbox Code Playgroud)

但是false没有Symbol.iterator方法。

您可以改用条件运算符,如果条件为假,则散布一个空数组:

let arr2 = ['value2', ...(condition && arr)];
Run Code Online (Sandbox Code Playgroud)

(这有效,因为空数组确实具有该Symbol.iterator方法)

对象传播是完全不同的:它将自己的可枚举属性从提供的对象复制到新的对象。false没有任何自己的可枚举属性,因此不会复制任何内容。


Nin*_*olz 17

false 不可传播。

您需要一个可扩展的对象(在其中Symbol.iterator实现的对象),如果已扩展,则不返回任何内容。

您可以使用一个空数组作为默认值。即使arr虚假的,这也有效

let condition = false;
let arr1 = ['value1'];
let arr2 = ['value2', ...(condition && arr || [])];

console.log(arr2);
Run Code Online (Sandbox Code Playgroud)

  • 我认为*这*是一个用例,其中`?:`更合适。;) (10认同)
  • 这实际上可以使用`?:`运算符,而不是链接的`||`。 (8认同)

tri*_*cot 11

这是对象文字和数组文字的扩展语法之间的规范差异。

MDN 在此简要提及-我强调:

传播语法(除了在传播属性的情况下)只能应用于可迭代对象

区别来自EcmaScript 2018规范:

  • 关于对象传播语法,请参见12.2.6.8运行时语义:PropertyDefinitionEvaluation

    • 它调用CopyDataProperties(object, fromValue, excludedNames)其中fromValue缠绕到与对象ToObject,因此变得可迭代,即使fromValue就像是一个原始值false。因此{...false}有效的 EcmaScript。
  • 关于数组扩展语法,请参见12.2.5.2运行时语义:ArrayAccumulation

    • 它仅调用GetValue(spreadRef)不进行上述包装的包装。因此,随后的调用GetIterator将触发原始值的错误,因为它是不可迭代的。因此[...false]无效的 EcmaScript。