Funkcinio programuotojo įvadas į „JavaScript“ (programinės įrangos kūrimas)

Dūmų meno kubai rūkyti - „MattysFlicks“ (CC BY 2.0)
PASTABA: Tai „Programinės įrangos kūrimo“ serijos (dabar knyga!), Susijusios su funkcinio programavimo ir kompozicinės programinės įrangos metodų mokymu „JavaSES6 +“, dalis nuo pat pradžių. Stebėkite. Tai dar daug daugiau!
Pirkite knygą | Rodyklė |

Tiems, kurie nepažįsta „JavaScript“ ar „ES6 +“, tai yra trumpa įžanga. Nesvarbu, ar esate pradedantysis, ar patyręs „JavaScript“ kūrėjas, galite išmokti ko nors naujo. Toliau yra tik skirta subraižyti paviršių ir jus sujaudinti. Jei norite sužinoti daugiau, jums tereikia tyrinėti giliau. Čia dar daug daugiau.

Geriausias būdas išmokti koduoti yra kodavimas. Aš rekomenduoju jums sekti naudojant interaktyvią „Java“ programavimo aplinką, tokią kaip „CodePen“ ar „Babel REPL“.

Arba galite atsikratyti naudodamiesi mazgu arba naršyklės pultu ATGAL.

Išraiškos ir vertybės

Išraiška yra kodo dalis, kuri įvertina reikšmę.

Šie visi „JavaScript“ galiojantys posakiai:

7;
7 + 1; // 8
7 * 2; // 14
'Sveiki'; // Sveiki

Išraiškos vertei gali būti suteiktas vardas. Tai padarius, pirmiausia įvertinama išraiška, o gauta reikšmė priskiriama pavadinimui. Tam naudosime raktinį žodį const. Tai ne vienintelis būdas, bet ir tas, kurį dažniausiai naudosite, todėl kol kas laikysimės const:

const hello = 'Sveiki';
Sveiki; // Sveiki

var, leisk, ir const

„JavaScript“ palaiko dar du kintamo deklaravimo raktinius žodžius: var ir let. Man patinka galvoti apie juos atrankos tvarka. Pagal numatytuosius nustatymus pasirenku griežčiausią deklaraciją: const. Kintamojo, deklaruojamo su raktiniu žodžiu const, negalima priskirti iš naujo. Galutinė vertė turi būti paskirta deklaravimo metu. Tai gali atrodyti nelanksti, tačiau apribojimas yra geras dalykas. Tai signalas, kuris jums sako: „šiam pavadinimui priskirta vertė nesikeis“. Tai padeda jums visiškai suprasti, ką vardas reiškia iškart, nereikia skaityti visos funkcijos ar blokuoti taikymo srities.

Kartais naudinga iš naujo priskirti kintamuosius. Pvz., Jei naudojate rankinį, imperatyvųjį iteravimą, o ne funkcionalesnį metodą, galite pakartoti skaitiklį, priskirtą su let.

Kadangi var pasako mažiausiai apie kintamąjį, tai yra silpniausias signalas. Nuo tada, kai pradėjau naudoti ES6, niekada sąmoningai nedeklaruoju vardo realiame programinės įrangos projekte.

Atminkite, kad kai kintamasis bus deklaruojamas su let arba const, bet koks bandymas pakartoti jį dar kartą sukels klaidą. Jei norite daugiau eksperimentinio lankstumo REPL (skaityti, vertinti, spausdinti ciklą) aplinkoje, kintamųjų deklaravimui galite naudoti var, o ne const. Leidžiamas perskaičiuoti var.

Šiame tekste bus naudojamas const, kad priverstumėte į nutylėjimą pasirinkti tikrąsias programas, tačiau interaktyviam eksperimentavimui galite laisvai pakeisti var.

Tipai

Iki šiol mes matėme du tipus: skaičius ir eilutes. „JavaScript“ taip pat turi booleans (tikros ar klaidingos), masyvus, objektus ir dar daugiau. Vėliau pateksime į kitas rūšis.

Masyvas yra užsakytas reikšmių sąrašas. Pagalvokite apie tai kaip dėžutę, kurioje būtų galima laikyti daug daiktų. Štai masyvo pažymi:

[1, 2, 3];

Žinoma, tai yra posakis, kuriam gali būti suteiktas vardas:

const arr = [1, 2, 3];

Objektas „JavaScript“ yra raktų: reikšmių porų rinkinys. Jame taip pat yra pažodinis žymėjimas:

{
  raktas: 'vertė'
}

Ir, žinoma, galite priskirti objektą pavadinimui:

const foo = {
  baras: 'baras'
}

Jei norite priskirti esamus kintamuosius to paties pavadinimo objekto nuosavybės klavišams, čia yra nuoroda. Galite tiesiog įvesti kintamojo pavadinimą, užuot pateikę raktą ir vertę:

const a = 'a';
const oldA = {a: a}; // ilgas, nereikalingas būdas
const oA = {a}; // trumpas saldus!

Pabandykime tai padaryti dar kartą:

const b = 'b';
const oB = {b};

Objektus galima lengvai sudėti į naujus objektus:

const c = {... oA, ... oB}; // {a: 'a', b: 'b'}

Tie taškai yra objekto paskirstymo operatorius. Jis pakartoja oA ypatybes ir priskiria jas naujam objektui, tada tą patį daro ir oB, nepaisydamas visų raktų, jau esančių naujame objekte. Nuo šio rašymo objekto sklaida yra nauja, eksperimentinė funkcija, kuri dar gali būti ne visose populiariose naršyklėse, tačiau jei ji jums neveikia, yra pakaitalas: Object.assign ():

const d = Object.assign ({}, oA, oB); // {a: 'a', b: 'b'}

Įrašykite tik šiek tiek daugiau pavyzdžių „Object.assign ()“ ir, jei rašote daug objektų, gali netgi šiek tiek sutaupyti. Atminkite, kad kai naudojate „Object.assign“ (), turite perduoti paskirties objektą kaip pirmąjį parametrą. Tai yra objektas, į kurį bus nukopijuotos savybės. Jei pamiršite ir praleisite paskirties objektą, objektas, kurį praleidote pateikdamas pirmąjį argumentą, bus mutavęs.

Mano patirtis rodo, kad egzistuojančio objekto mutacija, o ne naujo objekto sukūrimas yra klaida. Bent jau ji yra linkusi į klaidas. Būkite atsargūs naudodami „Object.assign“ ().

Pertvarkymas

Tiek objektai, tiek masyvai palaiko naikinimą, tai reiškia, kad galite iš jų išgauti reikšmes ir priskirti juos pavadintiems kintamiesiems:

const [t, u] = ['a', 'b'];
t; // 'a'
u; // 'b'
const blep = {
  blop: 'blop'
};

// Tai lygu:
// const blop = blep.blop;
const {blop} = pūsti;
blokas; // 'blokuoti'

Kaip ir aukščiau pateiktame masyvo pavyzdyje, jūs galite pertvarkyti kelias užduotis vienu metu. Štai eilutė, kurią matysite daugelyje „Redux“ projektų:

const {type, payload} = veiksmas;

Štai kaip jis naudojamas reduktoriaus kontekste (daug daugiau šia tema bus vėliau):

const myReducer = (būsena = {}, veiksmas = {}) => {
  const {type, payload} = veiksmas;
  jungiklis (tipas) {
    atvejis „FOO“: grąžinti „Object.assign“ ({}, būsena, naudingas krovinys);
    numatytoji: grąžinimo būsena;
  }
};

Jei nenorite naudoti kito pavadinimo naujam įrišimui, galite priskirti naują pavadinimą:

const {blop: bloop} = pūsti;
pūsti; // 'blokuoti'

Perskaitykite: priskirkite blep.blop kaip bloop.

Palyginimai ir ternarai

Galite palyginti reikšmes su griežtos lygybės operatoriumi (kartais vadinamu „trigubais lygiais“):

3 + 1 === 4; // tiesa

Taip pat yra aplaidus lygybės operatorius. Oficialiai jis žinomas kaip „lygus“ operatorius. Neoficialiai „dvigubai lygu“. Dviguba lygybė turi teisingą naudojimo atvejį ar du, tačiau beveik visada geriau numatyti, kad operatorius ===.

Kiti palyginimo operatoriai:

  • > Didesnis nei
  • > = Didesnis arba lygus
  • <= Mažesnis arba lygus
  • ! = Nelygu
  • ! == Ne griežtai lygus
  • && Loginiai ir
  • || Loginis arba

Tris kartus išreikšta išraiška yra išraiška, leidžianti užduoti klausimą naudojant lygintuvą, o atsakymas įvertinamas kitaip, atsižvelgiant į tai, ar išraiška yra teisinga, ar ne:

14 - 7 === 7? 'Taip!' : „Ne.“; // Taip!

Funkcijos

„JavaScript“ yra funkcijų išraiškos, kurias galima priskirti vardams:

const double = x => x * 2;

Tai reiškia tą patį, ką ir matematinė funkcija f (x) = 2x. Garsiai tariant, ta funkcija skaito f, kai x lygus 2x. Ši funkcija įdomi tik tada, kai pritaikote ją konkrečiai x vertei. Norėdami naudoti funkciją kitose lygtyse, parašykite f (2), kuri turi tą pačią reikšmę kaip 4.

Kitaip tariant, f (2) = 4. Apie matematikos funkciją galite galvoti kaip apie įvesties į išvesties atvaizdą. f (x) šiuo atveju yra x įvesties verčių atvaizdavimas atitinkamoms išvesties vertėms, lygioms įvesties vertės ir 2 sandaugai.

„JavaScript“ programoje funkcijos išraiškos vertė yra pati funkcija:

dvigubas; // [Funkcija: dviguba]

Funkcijos apibrėžimą galite pamatyti naudodami metodą .toString ():

double.toString (); // 'x => x * 2'

Jei norite pritaikyti funkciją kai kuriems argumentams, turite ją iškviesti su funkcijos skambučiu. Funkcijos skambutis pritaiko funkciją jos argumentams ir įvertina grįžtamąją vertę.

Funkciją galite iškviesti naudodamiesi (argumentas1, argumentas2, ... poilsis). Pvz., Norėdami panaudoti dvigubą funkciją, tiesiog pridėkite skliaustus ir duokite reikšmę dvigubai:

dvigubas (2); // 4

Skirtingai nuo kai kurių funkcinių kalbų, šios skliausteliai yra prasmingi. Be jų ši funkcija nebus vadinama:

dvigubas 4; // SyntaxError: netikėtas numeris

Parašai

Funkcijos turi parašus, kuriuos sudaro:

  1. Neprivalomas funkcijos pavadinimas.
  2. Parametrų tipų sąrašas skliausteliuose. Parametrai gali būti pavadinti.
  3. Grąžinamosios vertės tipas.

Tipo parašų nereikia nurodyti „JavaScript“. „JavaScript“ variklis išsiaiškins tipus vykdymo metu. Jei pateiksite pakankamai įkalčių, parašą taip pat gali nustatyti kūrėjo įrankiai, tokie kaip IDE (integruota kūrimo aplinka) ir Tern.js, naudodamiesi duomenų srauto analize.

„JavaScript“ trūksta savo funkcijos parašo žymėjimo, todėl yra keletas konkuruojančių standartų: JSDoc istoriškai buvo labai populiarus, tačiau jis yra nepatogiai aiškus ir niekas nesivargina nuolat atnaujinti dokumentų komentarų su kodu, todėl daugelis JS kūrėjų turi nustojo juo naudotis.

Šiuo metu didžiausi pretendentai yra „TypeScript“ ir „Flow“. Aš nesu tikras, kaip išreikšti viską, ko man reikia viename iš jų, todėl Rtype naudoju tik dokumentavimo tikslais. Kai kurie žmonės susigrąžina tik Haskell'o „Curley-Hindley – Milner“ tipus. Norėčiau pamatyti gerą „JavaScript“ žymėjimo sistemą, jei ji būtų naudojama tik dokumentais, tačiau nemanau, kad šiuo metu vienas iš dabartinių sprendimų atitinka užduotį. Kol kas susiraukite ir darykite viską, kad neatsiliktumėte nuo keisto tipo parašų, kurie tikriausiai atrodo šiek tiek kitaip, nei naudojate.

functionName (param1: Type, param2: Type) => Type

Dvigubas parašas yra:

dvigubas (x: n) => skaičius

Nepaisant to, kad „JavaScript“ nereikia pasirašyti parašų, žinios, kas yra parašai ir ką jie reiškia, vis tiek bus svarbu efektyviai pranešti apie tai, kaip naudojamos funkcijos ir kaip jos sudarytos. Daugumai pakartotinai naudojamų funkcijų kompozicijos priemonių reikia perduoti funkcijas, turinčias to paties tipo parašą.

Numatytosios parametrų vertės

„JavaScript“ palaiko numatytąsias parametrų reikšmes. Ši funkcija veikia kaip tapatybės funkcija (funkcija, kuri grąžina tą pačią vertę, kurią jūs įvedėte), nebent jūs ją vadinate neapibrėžtu ar tiesiog nepateikiate jokio argumento - tada ji grąžina nulį:

const orZero = (n = 0) => n;

Norėdami nustatyti numatytąją reikšmę, tiesiog priskirkite ją parametrui su = operatoriumi funkcijos parašuje, kaip nurodyta aukščiau n = 0. Kai tokiu būdu priskiriate numatytąsias vertes, rašymo išvadų įrankiai, tokie kaip „Tern.js“, „Flow“ ar „TypeScript“, gali automatiškai nustatyti jūsų funkcijos tipo parašą, net jei aiškiai nedeklaruojate tipo komentarų.

Rezultatas yra tas, kad įdiegę tinkamus papildinius į redaktorių arba IDE, galėsite matyti funkcijų parašus, rodomus inline, kai rašote funkcijų skambučius. Taip pat galėsite suprasti, kaip naudoti funkciją, remiantis jos skambučio parašu. Numatytųjų priskyrimų naudojimas visur, kur tikslinga, gali padėti parašyti daugiau savęs patvirtinančių kodų.

Pastaba: parametrai su numatytaisiais parametrais neįskaičiuojami į funkcijos ilgio savybę, kuri pašalins komunalines paslaugas, tokias kaip automatinė operacija, kurios priklauso nuo ilgio vertės. Kai kurios „curry“ programos (pvz., „Lodash“ / „curry“) leidžia perduoti pasirinktinę aritiją, kad būtų galima apeiti šį apribojimą, jei juo susipainiojate.

Pavadinta argumentais

„JavaScript“ funkcijos gali paimti objekto pažodus kaip argumentus ir naudoti destruktyvias užduotis parametro parašuose, kad būtų pasiektas pavadintų argumentų atitikmuo. Atkreipkite dėmesį, kad taip pat galite priskirti numatytąsias reikšmes parametrams naudodami numatytąją parametrų funkciją:

const createUser = ({
  vardas = „anonimas“,
  avatarThumbnail = '/avatars/anonymous.png'
}) => ({
  vardas,
  avatarThumbnail
});
const george = createUser ({
  vardas: „George“,
  avatarThumbnail: 'avatarai / atspalviai-emoji.png'
});
george;
/ *
{
  vardas: „George“,
  avatarThumbnail: 'avatarai / atspalviai-emoji.png'
}
* /

Poilsis ir skleidimasis

Bendras funkcijų „JavaScript“ bruožas yra galimybė surinkti likusių argumentų grupes funkcijų parašu naudojant poilsio operatorių: ...

Pvz., Ši funkcija paprasčiausiai atmeta pirmąjį argumentą, o likusią dalį pateikia kaip masyvą:

const aTail = (galva, ... uodega) => uodega;
„aTail“ (1, 2, 3); // [2, 3]

Poilsis surenka atskirus elementus į masyvą. Sklaida daro priešingai: paskirsto elementus iš masyvo į atskirus elementus. Apsvarstykite tai:

const shiftToLast = (galva, ... uodega) => [... uodega, galva];
„shiftToLast“ (1, 2, 3); // [2, 3, 1]

„JavaScript“ masyvuose yra iteratorius, kuris iškviečiamas, kai naudojamas paskirstymo operatorius. Kiekvienam masyvo elementui iteratorius pateikia vertę. Išraiškos [... uodega, galva] atveju iteratorius nukopijuoja kiekvieną elementą eilės tvarka iš uodegos masyvo į naują masyvą, kurį sukuria aplinkiniai pažodiniai žymėjimai. Kadangi galvutė jau yra atskiras elementas, mes tiesiog patepame ją ant masyvo galo ir viskas.

Kreivas

Kreivė yra funkcija, kuri vienu metu užima kelis parametrus: Ji paima parametrą ir grąžina funkciją, kuri imasi sekančio parametro, ir tt, kol bus pateikti visi parametrai. Tuo metu programa bus baigta ir grąžinama galutinė vertė.

„Curry“ ir „dalinis taikymas“ gali būti įjungiami sugrąžinus kitą funkciją:

const highpass = cutoff => n => n> = cutoff;
const gt4 = aukšta sparta (4); // highpass () grąžina naują funkciją

Jums nereikia naudoti rodyklių funkcijų. „JavaScript“ taip pat turi funkcijos raktinį žodį. Mes naudojame rodyklių funkcijas, nes funkcijos raktinis žodis yra daug labiau spausdinantis. Tai atitinka aukščiau pateiktą „highPass ()“ apibrėžimą:

const highpass = funkcija highpass (ribinė vertė) {
  grąžinimo funkcija (n) {
    grąža n> = ribinė vertė;
  };
};

„Java“ rodyklė maždaug reiškia „funkciją“. Yra keletas svarbių funkcijų elgsenos skirtumų, atsižvelgiant į tai, kokią funkciją naudojate (=> jai trūksta šios savybės ir jos negalima naudoti kaip konstruktoriaus), tačiau mes pateiksime tuos skirtumus, kai pateksime. Dabar, kai pamatysite x => x, pagalvokite apie „funkciją, kuri paima x ir grąžina x“. Taigi jūs galite perskaityti const highpass = cutoff => n => n> = cutoff; kaip:

„Aukšto lygio perėjimas yra funkcija, kuri atima ribą ir grąžina funkciją, kuri užima n ir grąžina n> = ribos rezultatą“.

Kadangi „highpass“ () grąžina funkciją, galite ją naudoti norėdami sukurti labiau specializuotą funkciją:

const gt4 = aukšta sparta (4);
gt4 (6); // tiesa
gt4 (3); // melagingas

„Autocurry“ suteikia galimybę automatiškai naudotis „curry“ funkcijomis, kad būtų maksimalus lankstumas. Tarkime, kad turite funkciją add3 ():

const add3 = karis ((a, b, c) => a + b + c);

Naudodamiesi automatine operacija, galite ją naudoti keliais skirtingais būdais, ir tai grąžins teisingą dalyką, atsižvelgiant į tai, kiek argumentų jūs perduosite:

add3 (1, 2, 3); // 6
add3 (1, 2) (3); // 6
add3 (1) (2, 3); // 6
add3 (1) (2) (3); // 6

Atsiprašome „Haskell“ gerbėjų, „JavaScript“ nėra įmontuoto automatinio kirpimo mechanizmo, tačiau galite jį importuoti iš „Lodash“:

Įdiekite $ npm - sutaupykite

Tuomet savo moduliuose:

importuoti karį iš 'lodash / curry';

Arba galite naudoti šį stebuklingą rašybą:

// Mažytė, pasikartojanti autokratija
const curry = (
  f, arr = []
) => (... args) => (
  a => a.length === f.length?
    f (... a):
    karis (f, a)
) ([... arr, ... arg.]);

Funkcijų sudėtis

Žinoma, jūs galite sudaryti funkcijas. Funkcijos sudarymas yra vienos funkcijos grąžinimo vertės kaip argumento kitai funkcijai perdavimas. Matematiškai:

f. g

Kas tai reiškia „JavaScript“:

f (g (x))

Tai vertinama iš vidaus:

  1. x įvertinamas
  2. g () taikomas x
  3. f () taikomas grįžtamosios vertės g (x)

Pavyzdžiui:

const inc = n => n + 1;
įsk. (dviguba (2)); // 5

2 reikšmė perduodama į dvigubą (), o tai sukuria 4. 4 perduodama į inc (), kuris įvertinamas iki 5.

Bet kurią išraišką kaip argumentą galite perduoti funkcijai. Išraiška bus įvertinta prieš pritaikant funkciją:

įsk. (dvigubas (2) * dvigubas (2)); // 17

Kadangi dvigubas (2) įvertinamas iki 4, galite perskaityti kaip inc (4 * 4), kuris įvertinamas iki inc (16), kuris tada įvertinamas iki 17.

Funkcijų kompozicija yra pagrindinė funkcinio programavimo dalis. Vėliau turėsime daug daugiau informacijos.

Masyvai

Masyvai turi keletą integruotų metodų. Metodas yra funkcija, susieta su objektu: paprastai susieto objekto ypatybė:

const arr = [1, 2, 3];
arr.map (dviguba); // [2, 4, 6]

Šiuo atveju arr yra objektas, .map () yra objekto savybė, turinti reikšmės funkciją. Kai jį iškviečiate, funkcija pritaikoma argumentams, taip pat specialus parametras, vadinamas šiuo, kuris automatiškai nustatomas, kai iškviečiamas metodas. Ši vertė yra tokia, kaip .map () gauna prieigą prie masyvo turinio.

Atminkite, kad dvigubą funkciją kaip vertę perduodame žemėlapiui, o ne ją vadiname. Taip yra todėl, kad žemėlapis funkciją laiko argumentu ir taiko ją kiekvienam masyvo elementui. Tai grąžina naują masyvą, kuriame yra vertės, grąžintos dvigubai ().

Atminkite, kad pradinė arr reikšmė nesikeičia:

arr; // [1, 2, 3]

Metodo sujungimas

Taip pat galite suskirstyti metodo skambučius. Metodo sujungimas yra metodas, kuriuo tiesiogiai iškviečiamas funkcijos grįžtamoji vertė, nereikia nurodyti grįžtamosios vertės pagal pavadinimą:

const arr = [1, 2, 3];
arr.map (dviguba) .map (dviguba); // [4, 8, 12]

Predikatas yra funkcija, kuri grąžina loginę reikšmę (teisinga arba klaidinga). .Filter () metodas paima predikatą ir grąžina naują sąrašą, pasirinkdamas tik tuos elementus, kurie praeina predikatą (grįžta tiesa), kad būtų įtraukti į naują sąrašą:

[2, 4, 6] .filtras (gt4); // [4, 6]

Dažnai norėsite pasirinkti elementus iš sąrašo ir susieti juos su naujais sąrašais:

[2, 4, 6] .filtras (gt4) .map (dvigubas); [8, 12]

Pastaba: vėliau šiame tekste pamatysite veiksmingesnį būdą tuo pačiu metu pasirinkti ir žemėlapiuoti naudojant tai, kas vadinama keitikliu, tačiau pirmiausia yra ir kitų dalykų.

Išvada

Jei jūsų galva sukasi dabar, nesijaudinkite. Mes vos neišgryninome daugelio dalykų, kurie verti daug daugiau tyrinėjimo ir apsvarstymo, paviršiaus. Greitai susisieksime ir panagrinėsime kai kurias iš šių temų.

Pirkite knygą | Rodyklė |

Sužinokite daugiau EricElliottJS.com

„EricElliottJS.com“ nariams yra siūlomos vaizdo įrašų pamokos su interaktyviais kodo iššūkiais. Jei nesate narys, prisiregistruokite šiandien.

Erikas Elliotas yra paskirstytų sistemų ekspertas ir knygų „Programinės įrangos kūrimas“ ir „Programų programavimas„ JavaScript “programose“ autorius. Kaip „DevAnywhere.io“ įkūrėjas, jis moko kūrėjus įgūdžių, reikalingų dirbant nuotoliniu būdu ir pritaikant darbo ir asmeninio gyvenimo pusiausvyrą. Jis kuria ir pataria kriptovaliutų kūrimo komandoms bei prisideda prie programinės įrangos patirties „Adobe Systems“, „Zumba Fitness“, „The Wall Street Journal“, ESPN, BBC ir geriausių įrašų atlikėjų, įskaitant Usherį, Franką Okeaną, „Metallica“ ir daugelį kitų.

Jis mėgsta nuotolinį gyvenimo būdą su gražiausia moterimi pasaulyje.