Добавить элементы в массиве условно в JavaScript

Когда я пытаюсь объединить два объекта, используя условный оператор распространения, он работает, когда условие true или false:

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

// obj2 = {key2: 'value2'};

Когда я пытаюсь использовать ту же логику, с массивами, она работает только тогда, когда условие true:

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

// arr2 = ['value2', 'value1']

Если условие false выдается ошибка:

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

// Error

Ответ 1

Когда вы распространяетесь в массив, вы вызываете метод Symbol.iterator для объекта. && оценивает первое значение Ложи (или последнее истинное значение, если все верно), поэтому

let arr2 = ['value2', ...(condition && arr)];

результаты в

let arr2 = ['value2', ...(false)];

Но false не имеет метода Symbol.iterator.

Вместо этого вы можете использовать условный оператор и распространять пустой массив, если условие ложно:

let condition = false;
let arr1 = ['value1'];
let arr2 = ['value2', ...(condition ? arr1 : [])];
console.log(arr2);

Ответ 2

false не распространяется

Вам нужен расширяемый объект (тот, в котором реализован Symbol.iterator), который ничего не возвращает, если распространяется.

Вы можете использовать пустой массив в качестве значения по умолчанию. Это работает, даже если arr ложно.

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

console.log(arr2);

Ответ 3

Это специфика различий между синтаксисом распространения для литералов объекта и литералов массива.

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.