Добавить элементы в массиве условно в JavaScript - PullRequest
44 голосов
/ 07 мая 2019

Когда я пытаюсь объединить два объекта с помощью оператора распространения по условию, он работает, когда условие 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

Почему поведение отличается между Array и Object?

Ответы [ 3 ]

46 голосов
/ 07 мая 2019

Когда вы распространяетесь в массив , вы вызываете метод 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);

(Это работает, потому что пустой массив имеет метод Symbol.iterator)

Распространение объекта полностью отличается: копирует собственные перечисляемые свойства из предоставленного объекта в новый объект.false не имеет собственных перечисляемых свойств, поэтому ничего не копируется.

17 голосов
/ 07 мая 2019

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

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

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

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

console.log(arr2);
11 голосов
/ 07 мая 2019

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

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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...