Conditionally add elements into the Javascript Array

Asked

Viewed 201 times

4

When I try to merge two objects using the operator spread conditionally, it works perfectly with both conditions 'true' and 'false':

let condition1 = false;
let condition2 = true;
let obj1 = {
  key1: 'value1'
};
let obj2 = {
  key2: 'value2',
  ...(condition1 && obj1),
};
let obj3 = {
  key3: 'value3'
};
let obj4 = {
  key4: 'value4',
  ...(condition2 && obj3),
};

console.log(obj2); // {key2: 'value2'}
console.log(obj4); // {key4: "value4", key3: "value3"}

When I try to use the same logic with Arrays, only works when the condition is true 'true':

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

console.log(arr2); // ['value2', 'value1']

If the condition is false 'false', an error will be cast:

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

console.log(arr2); // Error

Why behavior is different between Array and Object?

  • Running your code did not cause the error, try running: https://es6console.com/jvrzeln3/

  • @Thiagokrempser, interestingly the code does not generate any error in es6console.with, but this does not solve the question because in others it browsers/compilers generates.

2 answers

1


then let’s explain:

  • First let’s understand the ternary and logical conditionals:

    Well, the condition you tried to implement in your code is logic, that is, it checks if a certain condition is met and only then performs an action or assigns a value. In the case of logic && happens as if it were an if, but without Else and if the condition is not satisfied it will return Undefined, try:

// Lógico &&
// condição && se true
console.log('Lógico &&');

let cond = false;

const valueUndef = cond && 'teste'; // undefined/false

cond = true;

const valueDef = cond && 'teste'; // 'teste'

console.log(valueUndef);
console.log(valueDef);

// Ternário ?
// condição ? se true : se false
console.log('Ternário ?');

cond = false;

const valueDefOrUndef1 = cond ? 'cond true' : 'cond false';

cond = true;

const valueDefOrUndef2 = cond ? 'cond true' : 'cond false';

console.log(valueDefOrUndef1);
console.log(valueDefOrUndef2);

  • Now we will see why it works on literal objects and not arrays:

    Well, first you need to know that although both are objects, they have distinct behaviors and also react differently to the spread, so while the spread in an array expects to receive an iterable element(String, Array, Typedarray, Map and Set) the spread on a literal object only expects to receive any object and uses internally the Object.values, Object.Keys and/or Object.Entries functionality to capture the props and values of that object to incorporate it. Examples:

// Objeto literal

const obj1 = { k1: 1 };
const obj2 = { k2: 2 };
const obj3 = { k3: 3 };
const obj4 = { k4: 4 };

const obj5 = { k5: 5, ...(true && obj1), ...(false && obj2) }

console.log(obj5);

// Internamente o que aconteceu aqui foi mais ou menos isso:

const obj3Keys = Object.keys(obj3);
const obj3Values = Object.values(obj3);

obj3Keys.forEach((v, i) => {
  obj4[v] = obj3Values[i];
});

console.log(obj4);

/* Ao receber o false como retorno da operação lógica e tentar
pegar suas props e values ele simplesmente retornou um iterable
vazio pois este objeto não tem props e values legíveis. */

console.log(Object.keys(false));
console.log(Object.values(false));

/* Sendo assim o spread funcionou como deveria para o objeto
mesmo não passando na condição, pois tentou espalhar o iterable
vazio e obviamente não incrementou nenhuma prop ou value por
conta deste fato. */

// Array

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [...(true && arr1)];
console.log(arr3);

const arr4 = [...(false && arr2)];
console.log(arr4);

/* Utilizando a operação lógica neste caso você tem um efeito
inesperado, na primeira situação para o caso true tudo deve
correr normalmente, porém na segunda situação para o caso false
devemos ter um erro dizendo que não foi possível iterar sobre o
elemento estipulado. */

  • Understanding what has happened...

    This happens because the spread in the array expects to receive a uniquely iterable object (String, Array, Typedarray, Map, and Set) and searches for a unique property of each array and hides it called Symbol.iterator to use it to iterate over the structure. Since the objects usually returned in the negation of the logical operation are false; Undefined and null, then they are not eternal, which results in the system error. This can be easily solved with a composite logic operation or with the ternary itself. Examples:

const arr1 = [1, 2];
const arr2 = [3, 4];

const arr3 = [...(false && arr1 || [5, 6])];

console.log(arr3);
/* Retornou false na primeiro operação, porém por ser uma
operação composta com uma alternativa or(||) eu consegui enviar outro elemento para ser iterado. */

const arr4 = [...(false ? arr2 : [])];

console.log(arr4);
/* Aqui da mesma forma retornou false, porém utlizando o ternário
eu pude gerar uma alternativa vazia para a condição, para que
tudo corresse normalmente mas nenhum valor fosse adicionado. */

0

Try it this way:

let conditional = false;
let arr4 = ['value2', ...(condition ? arr1 : [])];

  • Do you mind editing the code to make it work and also explain why this solution.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.