6 consells útils per escriure condicionals millors a JavaScript

Bloc

6 consells útils per escriure condicionals millors a JavaScript

6 consells útils per escriure condicionals millors a JavaScript

En qualsevol llenguatge de programació, el codi ha de prendre decisions i executar accions en funció de la condició indicada a l'entrada.

Per exemple, en un joc, si el nombre de vides del jugador és de 0, el joc s’ha acabat. En una aplicació meteorològica, si es mira al matí, mostreu un gràfic de sortida del sol; mostrar estrelles i una lluna si és de nit. En aquest article, explorarem com funcionen les anomenades afirmacions condicionals JavaScript .

Si treballes amb JavaScript , escrivireu un munt de codi amb molts condicionants implicats. Els condicionants poden semblar fàcils d’aprendre al principi, però hi ha més que escriure un parell de if/else declaracions. Aquests són alguns consells útils per escriure un codi millor i més net amb condicionals.

comprar bytecoin amb usd

Taula de continguts

  1. Array.inclou
  2. Sortida anticipada / Tornada aviat
  3. Objecte literal o mapa en lloc de declaració de commutador
  4. Paràmetres i desestructuració per defecte
  5. Feu coincidir tots els criteris / parcials amb Array.every i Array.some
  6. Utilitzeu un encadenament opcional i una coalescència nul·la

1. Matriu.inclou

Utilitzeu Array.includes per a diverses condicions

Per exemple:

function printAnimals(animal) { if (animal === 'dog' || animal === 'cat') { console.log(`I have a ${animal}`); } } console.log(printAnimals('dog')); // I have a dog

El codi anterior es veu bé, ja que només tenim dos animals per comprovar. Tot i això, no estem segurs de l’entrada de l’usuari. I si aconseguim algun altre animal? Si seguirem ampliant la declaració amb més OR sentències, el codi serà més difícil de mantenir i no tan net.

Solució:

Podem reescriure el condicional anterior mitjançant Array.includes

function printAnimals(animal) { const animals = ['dog', 'cat', 'hamster', 'turtle']; if (animals.includes(animal)) { console.log(`I have a ${animal}`); } } console.log(printAnimals('hamster')); // I have a hamster

Aquí hem creat un conjunt d’animals perquè les condicions s’extreuen per separat de la resta del codi. Ara, si volem fer una comprovació per a qualsevol altre animal, tot el que hem de fer és afegir un element de matriu nou.

També podem utilitzar el animals variable fora de l'abast d'aquesta funció per tornar-la a utilitzar en qualsevol altre lloc del codi. Aquesta és una manera d’escriure codi més net que és més fàcil d’entendre i mantenir. No és així?

2. Sortida anticipada / Tornada anticipada

Aquest és un truc molt interessant per condensar el vostre codi i fer que sembli més net. Recordo que quan vaig començar a treballar professionalment, vaig aprendre a escriure condicionals amb early exit el meu primer dia.

Prenem l'exemple anterior i afegim algunes condicions més. Què passa si en lloc de l’animal com un simple string, és un object amb certes propietats.

Ara els requisits són:

  • Si no hi ha cap animal, llança un error
  • Imprimiu el tipus d’animal
  • Imprimiu el nom de l'animal
  • Imprimiu el gènere de l'animal
const printAnimalDetails = animal => { let result; // declare a variable to store the final value // condition 1: check if animal has a value if (animal) { // condition 2: check if animal has a type property if (animal.type) { // condition 3: check if animal has a name property if (animal.name) { // condition 3: check if animal has a gender property if (animal.gender) { result = `${animal.name} is a ${animal.gender} ${animal.type};`; } else { result = 'No animal gender'; } } else { result = 'No animal name'; } } else { result = 'No animal type'; } } else { result = 'No animal'; } return result; }; console.log(printAnimalDetails()); // 'No animal' console.log(printAnimalDetails({ type: 'dog', gender: 'female' })); // 'No animal name' console.log(printAnimalDetails({ type: 'dog', name: 'Lucy' })); // 'No animal gender' console.log( printAnimalDetails({ type: 'dog', name: 'Lucy', gender: 'female' }) ); // 'Lucy is a female dog'

Què en penseu del codi anterior?

Funciona bé, però el codi és llarg i difícil de mantenir. Es pot perdre el temps esbrinant on es troben els claudàtors de tancament si tampoc no fan servir pelusses. Imagineu què passaria si el codi té una lògica més complexa. Un munt de if..else declaracions!

Podem refactoritzar la funció anterior amb operadors ternaris, && condicions, etc., però escrivim un codi més precís mitjançant l'ús de múltiples declaracions de retorn.

const printAnimalDetails = ({type, name, gender } = {}) => { if(!type) return 'No animal type'; if(!name) return 'No animal name'; if(!gender) return 'No animal gender'; // Now in this line of code, we're sure that we have an animal with all the three properties here. return `${animal.name} is a ${animal.gender} ${animal.type}`; } console.log(printAnimalDetails()); // 'No animal' console.log(printAnimalDetails({ type: dog })); // 'No animal name' console.log(printAnimalDetails({ type: dog, gender: female })); // 'No animal name' console.log(printAnimalDetails({ type: dog, name: 'Lucy', gender: 'female' })); // 'Lucy is a female dog'

A la versió refactoritzada, destructuring i default parameters també s'inclou. El paràmetre per defecte garanteix que si passem undefined com a argument del mètode, encara tenim un valor per destruir, que és un objecte buit {}.

Normalment, en el món professional, el codi s’escriu en algun lloc entre aquests dos enfocaments. Molta gent considera if...else afirmacions més fàcils d'entendre.

matriu javascript afegeix matriu

Un altre exemple:

function printVegetablesWithQuantity(vegetable, quantity) { const vegetables = ['potato', 'cabbage', 'cauliflower', 'asparagus']; // condition 1: vegetable should be present if (vegetable) { // condition 2: must be one of the item from the list if (vegetables.includes(vegetable)) { console.log(`I like ${vegetable}`); // condition 3: must be large quantity if (quantity >= 10) { console.log('I have bought a large quantity'); } } } else { throw new Error('No vegetable from the list!'); } } printVegetablesWithQuantity(null); // error: No fruits printVegetablesWithQuantity('cabbage'); // print: red printVegetablesWithQuantity('cabbage', 20); // 'I like cabbage` // 'I have bought a large quantity'

Ara, mireu el codi anterior, tenim:

  • 1 sentència if / else que filtra la condició no vàlida
  • 3 nivells d'instruccions imbricades (condició 1, 2 i 3)

Una regla general a seguir és return early when invalid conditions found.

function printVegetablesWithQuantity(vegetable, quantity) { const vegetables = ['potato', 'cabbage', 'cauliflower', 'asparagus']; // condition 1: throw error early if (!vegetable) throw new Error('No vegetable from the list!'); // condition 2: must be in the list if (vegetables.includes(vegetable)) { console.log(`I like ${vegetable}`); // condition 3: must be a large quantity if (quantity >= 10) { console.log('I have bought a large quantity'); } } }

En fer-ho, tenim un nivell menys de la sentència imbricada. Aquest estil de codificació és bo sobretot si teniu declaració long if.

Podem reduir encara més la nidificació if s, invertint les condicions i tornant aviat. Mireu l'estat 2 següent per veure com ho fem:

function printVegetablesWithQuantity(vegetable, quantity) { const vegetables = ['potato', 'cabbage', 'cauliflower', 'asparagus']; if (!vegetable) throw new Error('No vegetable from the list!'); // condition 1: throw error early if (!vegetables.includes(vegetable)) return; // condition 2: return from the function is the vegetable is not in the list console.log(`I like ${vegetable}`); // condition 3: must be a large quantity if (quantity >= 10) { console.log('I have bought a large quantity'); } }

Invertint les condicions de la condició 2, el codi ja no té una sentència imbricada. Aquesta tècnica és útil quan tenim moltes condicions i volem aturar el procés posterior quan no es compleixi cap condició particular.

Tot i això, no hi ha una regla difícil per fer-ho. Podeu deixar-la com a versió anterior (condició 2 amb imbricada), perquè:

El codi és curt i directe, és més clar amb if s imbricats.
Les condicions d'inversió poden comportar més càrrega cognitiva i de pensament per als desenvolupadors a la llarga.

Per tant, sempre busqueu Less Nesting i Return Early però no us en excediu.

3. Objecte literal o mapa en lloc de declaració de commutador

Vegem l'exemple següent: volem imprimir fruites en funció del color:

function printFruits(color) { // use switch case to find fruits by color switch (color) { case 'red': return ['apple', 'strawberry']; case 'yellow': return ['banana', 'pineapple']; case 'purple': return ['grape', 'plum']; default: return []; } } printFruits(null); // [] printFruits('yellow'); // ['banana', 'pineapple']

El codi anterior no està malament, però encara és força detallat. El mateix resultat es pot aconseguir amb object literal amb una sintaxi més neta:

acomiadaments de ciències de dades d’informació
// use object literal to find fruits by color const fruitColor = { red: ['apple', 'strawberry'], yellow: ['banana', 'pineapple'], purple: ['grape', 'plum'] }; function printFruits(color)

Com a alternativa, podeu utilitzar Map per aconseguir el mateix resultat:

// use Map to find fruits by color const fruitColor = new Map() .set('red', ['apple', 'strawberry']) .set('yellow', ['banana', 'pineapple']) .set('purple', ['grape', 'plum']); function printFruits(color) [];

Map és el tipus d'objecte disponible des de l'ES2015, que permet emmagatzemar el key-value parella.

Per a l'exemple anterior, es pot aconseguir el mateix resultat amb Array.filter també.

const fruits = [ { name: 'apple', color: 'red' }, { name: 'strawberry', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'pineapple', color: 'yellow' }, { name: 'grape', color: 'purple' }, { name: 'plum', color: 'purple' } ]; function printFruits(color) { return fruits.filter(fruit => fruit.color === color); }

4. Paràmetres i desestructuració per defecte

Mentre treballem amb JavaScript, sempre hem de buscar null/undefined valorar i assignar default value, o els salts de compilació.

function printVegetablesWithQuantity(vegetable, quantity = 1) { // if quantity has no value, assign 1 if (!vegetable) return; console.log(`We have ${quantity} ${vegetable}!`); } //results printVegetablesWithQuantity('cabbage'); // We have 1 cabbage! printVegetablesWithQuantity('potato', 2); // We have 2 potato!

Molt més fàcil i intuïtiu, oi?

Què passa si vegetable és un objecte? Podem assignar un paràmetre per defecte?

function printVegetableName(vegetable) { if (vegetable && vegetable.name) { console.log (vegetable.name); } else { console.log('unknown'); } } printVegetableName(undefined); // unknown printVegetableName({}); // unknown printVegetableName({ name: 'cabbage', quantity: 2 }); // cabbage

A l’exemple anterior, volem imprimir el nom de la verdura si està disponible o imprimir unknown.

Podem evitar el condicional if (vegetable && vegetable.name) {} mitjançant l'ús de paràmetres i destrucció per defecte.

com veure algú privat a twitter
// destructing - get name property only // assign default empty object {} function printVegetableName({name} = {}) 'unknown'); printVegetableName(undefined); // unknown printVegetableName({ }); // unknown printVegetableName({ name: 'cabbage', quantity: 2 }); // cabbage

Com que només necessitem propietats name, podem desestructurar el paràmetre mitjançant { name }, llavors podem utilitzar name com a variable al nostre codi en lloc de vegetable.name.

També assignem un objecte buit {} com a valor per defecte; en cas contrari, es produirà un error en executar la línia printVegetableName(undefined) - Cannot destructure property name of undefined or null, perquè no hi ha cap propietat de nom a undefined.

5. Feu coincidir tots els criteris / parcials amb Array.every i Array.some

Aquest consell tracta més d’utilitzar mètodes Javascript Array no tan nous per reduir les línies de codi. Mireu el codi següent, volem comprovar si totes les fruites són de color vermell:

const fruits = [ { name: 'apple', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'grape', color: 'purple' } ]; function test() { let isAllRed = true; // condition: all fruits must be red for (let f of fruits) { if (!isAllRed) break; isAllRed = (f.color == 'red'); } console.log(isAllRed); // false }

El codi és molt llarg. Podem reduir el nombre de línies amb Array.every:

const fruits = [ { name: 'apple', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'grape', color: 'purple' } ]; function test() { // condition: short way, all fruits must be red const isAllRed = fruits.every(f => f.color == 'red'); console.log(isAllRed); // false }

Molt més net ara no? De manera similar, si volem provar si alguna de les fruites és vermella, podem utilitzar Array.some per aconseguir-la en una línia.

const fruits = [ { name: 'apple', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'grape', color: 'purple' } ]; function test() { // condition: if any fruit is red const isAnyRed = fruits.some(f => f.color == 'red'); console.log(isAnyRed); // true }

6. Utilitzeu un encadenament opcional i una coalescència nul·la

Aquesta part encara no s’utilitza molt, però vull incloure-la als meus consells per escriure millors condicionants. Aquestes dues funcionalitats són una addició molt útil a JavaScript.

En el moment d’escriure això, aquestes opcions no eren totalment compatibles i calia utilitzar Babel per compilar el codi.

Optional chaining ens permet gestionar estructures semblants a l'arbre sense comprovar explícitament si existeixen nodes intermedis i nullish coalescing funciona molt bé en combinació amb un encadenament opcional i s’utilitza per assegurar el valor predeterminat d’un inexistent.

Mostrem alguns exemples:

const car = { model: 'Fiesta', manufacturer: { name: 'Ford', address: { street: 'Some Street Name', number: '5555', state: 'USA' } } } // to get the car model const model = car && car.model || 'default model'; // to get the manufacturer street const street = car && car.manufacturer && car.manufacturer.address && car.manufacturer.address.street || 'default street'; // request an un-existing property const phoneNumber = car && car.manufacturer && car.manufacturer.address && car.manufacturer.phoneNumber; console.log(model) // 'Fiesta' console.log(street) // 'Some Street Name' console.log(phoneNumber) // undefined

Per tant, si volguéssim imprimir si el fabricant de vehicles és dels EUA, el codi tindria un aspecte semblant a aquest:

const isManufacturerFromUSA = () => { if(car && car.manufacturer && car.manufacturer.address && car.manufacturer.address.state === 'USA') { console.log('true'); } } checkCarManufacturerState() // 'true'

Podeu veure clarament el desordenat que pot esdevenir en cas d’una estructura d’objectes més complexa. Moltes biblioteques, com lodash, per exemple, tenen les seves pròpies funcions com a solucions, però no ho volem, ho volem fer en vainilla js. Vegem una nova manera de fer les coses.

// to get the car model const model = car?.model ?? 'default model'; // to get the manufacturer street const street = car?.manufacturer?.address?.street ?? 'default street'; // to check if the car manufacturer is from the USA const isManufacturerFromUSA = () => { if(car?.manufacturer?.address?.state === 'USA') { console.log('true'); } }

Sembla molt més bonic i fàcil de mantenir. Ja és a la fase 3 de TC39, esperem que s’aprovi i després podrem veure l’ús d’aquesta increïble sintaxi a tot arreu.

Resum

Aprenem i provem nous consells i tècniques per escriure un codi més net i mantenible, perquè, al cap d’uns mesos, els condicionaments llargs poden ser com disparar-se al peu.

#javascript