Koodausvinkki: Yritä koodata ilman If-lauseita

Saatat löytää parempia ratkaisuja

Koodi Facebook-projektista. Älä haasta heitä.
Päivitys: Tämä artikkeli on nyt osa kirjaa “Opi koodaus nykyaikaisella JavaScriptillä”.
Lue sen päivitetty versio osoitteesta jscomplete.com/no-ifs.

Kun opetan aloittelijoita ohjelmoimaan ja esittämään heille koodiin liittyviä haasteita, yksi suosikki seurannan haasteista on: Ratkaise nyt sama ongelma käyttämättä if-lauseita (tai kolmen operaattorin tai vaihda lauseita).

Saatat kysyä, miksi siitä olisi hyötyä?

No, mielestäni tämä haaste pakottaa aivosi ajattelemaan toisin ja joissakin tapauksissa erilainen ratkaisu saattaa olla parempi.

If-lauseiden käyttämisessä ei ole mitään vikaa, mutta niiden välttäminen voi joskus tehdä koodista hieman luettavamman ihmisille. Tämä ei todellakaan ole yleinen sääntö, koska joskus vältetään jos lauseet tekevät koodista paljon vähemmän luettavissa. Sinä olet tuomari.

Jos lauseiden välttäminen ei ole pelkästään luettavuutta. Käsitteen takana on tiedettä. Kuten alla olevat haasteet osoittavat, jos if-lauseiden käyttäminen vie sinut lähemmäksi code-as-data -käsitettä, joka avaa oven ainutlaatuisille ominaisuuksille, kuten koodin muuttamiselle sen suorittamisen aikana!

Kaikissa tapauksissa on aina hauskaa yrittää ratkaista koodaushaaste ilman mitään ehdollisia ehtoja.

Tässä on esimerkkejä haasteista niiden if-pohjaisten ja if-less-ratkaisujen kanssa. Kaikki ratkaisut on kirjoitettu JavaScriptiin.

Kerro, mitkä ratkaisut ovat mielestäsi luettavissa olevia.

Haaste # 1: Laske pariton kokonaisluku taulukossa

Oletetaan, että meillä on joukko kokonaislukuja ja haluamme laskea kuinka moni näistä kokonaisluvuista on pariton.

Tässä on esimerkki testattavaksi:

const-taulukkoOfIntegers = [1, 4, 5, 9, 0, -1, 5];

Tässä on ratkaisu, joka käyttää if-lauseketta:

laske laskuri = 0;
arrayOfIntegers.forEach ((kokonaisluku) => {
  const jäljellä = Math.abs (kokonaisluku% 2);
  if (loput === 1) {
    laskuri ++;
  }
});
console.log (laskuri);

Tässä on ratkaisu ilman if-lauseita:

laske laskuri = 0;
arrayOfIntegers.forEach ((kokonaisluku) => {
  const jäljellä = Math.abs (kokonaisluku% 2);
  laskuri + = jäännös;
});
console.log (laskuri);

Huomaa: yllä olevissa esimerkeissä käytetään jokaiselle ja mutatoidaan laskurimuuttuja. On puhtaampaa ja turvallisempaa käyttää sen sijaan muuttumattomia menetelmiä. Tämä artikkeli ei kuitenkaan koske tätä aihetta. Pysy ajan tasalla lisää koodausvihjeartikkeleita varten, jotka kattavat muuttumattomuuden ja toiminnallisen ohjelmoinnin. Huomaa myös, kuten David Nagli on korostanut, että if-less-ratkaisu toimisi vain kokonaislukuissa, kun taas if-pohjaisen ratkaisun etuna on se, että se käsittelee mitä tahansa lukuja, myös desimaalilukuja.

Jos ratkaisu on vähemmän, käytämme hyväksi sitä tosiasiaa, että moduulin 2 toiminnan tulos on aina joko 1 (pariton) tai 0 (parillinen). Tämä tulos on tietoa. Käytimme vain tietoja suoraan.

Entä jos lasketaan jopa kokonaislukuja? Voitko ajatella tapaa tehdä tämä käyttämättä if-lauseketta?

Haaste # 2: viikonloppuOrWeekday -toiminto

Kirjoita toiminto, joka ottaa päivämääräobjektiargumentin (kuten uusi päivämäärä ()) ja palauttaa merkkijonon “viikonloppu” tai “viikonpäivä”.

Tässä on ratkaisu, joka käyttää if-lauseketta:

const weekendOrWeekday = (inputDate) => {
  vakiopäivä = inputDate.getDay ();
  if (päivä === 0 || päivä === 6) {
    paluu 'viikonloppu';
  }
  
  palata 'arkipäivä';
  // Tai kolmiosaisten faneille:
  // paluu (päivä === 0 || päivä === 6)? 'viikonloppu': 'viikonpäivä';
};
console.log (weekendOrWeday (uusi päivämäärä ()));

Tässä on ratkaisu ilman if-lauseita:

const weekendOrWeekday = (inputDate) => {
  vakiopäivä = inputDate.getDay ();
  palaa viikonloppuOrWeekday.labels [päivä] ||
         weekendOrWeekday.labels [ 'default'];
};
weekendOrWeekday.labels = {
  0: 'viikonloppu',
  6: 'viikonloppu',
  oletus: 'arkipäivä'
};
console.log (weekendOrWeday (uusi päivämäärä ()));

Huomasitko, että if-lause-ehossa on joitain tietoja siinä? Se kertoo meille, mitkä päivät ovat viikonloppuja. Mitä teimme välttääksesi if-lauseen, on purkaa kyseiset tiedot objektiin ja käyttää sitä suoraan. Tämä antaa meille myös mahdollisuuden tallentaa tiedot korkeammalle yleiselle tasolle.

Päivitys: Harald Niesche huomautti oikein, että || yllä oleva temppu on teknisesti ehdollinen asia. Olen valinnut sen käytön niin, että en toista ”arkipäivää” viisi kertaa. Voimme päästä eroon siitä, jos laitamme koko 7 päivää tarra-esineeseen.

Haaste # 3: Tupla-toiminto (tässä lohikäärmeet)

Kirjoita kaksinkertainen toiminto, joka sen tulon tyypin perusteella toimisi seuraavasti:

  • Kun syöte on luku, se kaksinkertaistaa sen (ts. 5 => 10, -10 => -20).
  • Kun syöte on merkkijono, se toistaa jokaisen kirjaimen (ts. 'Hello' => 'hheelloo').
  • Kun tulo on toiminto, se kutsuu sitä kahdesti.
  • Kun syöte on taulukko, se kutsuu itsensä kaikkiin sen taulukon elementteihin.
  • Kun sisääntulo on objekti, se kutsuu itseään kaikki kyseisen objektin arvot.

Tässä on ratkaisu, joka käyttää kytkinlauseketta:

const doubler = (sisääntulo) => {
  kytkin (tulotyyppi) {
    tapaus numero':
      paluu tulo + tulo;
    tapaus 'merkkijono':
      palauta syöttö
        .jakaa('')
        .map ((kirje) => kirjain + kirjain)
        .liittyä seuraan('');
    tapaus 'esine':
      Object.keys (tulo)
            .map ((näppäin) => (syöttö [avain] = kaksinkertainen (syöttö [näppäin])));
      paluu tulo;
    tapaus 'toiminto':
      tulo ();
      tulo ();
  }
};
console.log (tuplaaja (-10));
console.log (kahdentaja ( 'hei'));
console.log (doubler ([5, 'hello']));
console.log (doubler ({a: 5, b: 'hello'}));
console.log (
  tupla (toiminto () {
    console.log (call me ");
  }),
);

Tässä on ratkaisu ilman kytkinlausetta:

const doubler = (sisääntulo) => {
  return doubler.operationsByType [typeof input] (input);
};
doubler.operationsByType = {
  numero: (tulo) => tulo + tulo,
  merkkijono: (syöttö) =>
    panos
      .jakaa('')
      .map ((kirje) => kirjain + kirjain)
      .liittyä seuraan(''),
  toiminto: (tulo) => {
    tulo ();
    tulo ();
  },
  objekti: (input) => {
    Object.keys (tulo)
          .map ((näppäin) => (syöttö [avain] = kaksinkertainen (syöttö [näppäin])));
    paluu tulo;
  },
};
console.log (tuplaaja (-10));
console.log (kahdentaja ( 'hei'));
console.log (doubler ([5, 'hello']));
console.log (doubler ({a: 5, b: 'hello'}));
console.log (
  tupla (toiminto () {
    console.log (call me ");
  }),
);

Huomaa taas, kuinka kaikki tiedot (mitkä operaatiot tulisi suorittaa mistä syöttötyypille) on kaikki poistettu kytkinlausekkeesta objektiin. Sitten objektia käytettiin oikean toiminnan valintaan ja vetoamiseen alkuperäiseen syöttöön.

Nyt kun olet nähnyt muutamia esimerkkejä, mitä ajattelet? Onko sinulla väitteitä näiden kahden koodaustyylin puolesta tai vastaan?

Kiitos käsittelystä.