Funktsionaalne programmeerimine on arvutiprogrammide loomise paradigma, kasutades väljendeid ja funktsioone ilma seisundit ja andmeid muteerimata.
Nendest piirangutest kinni pidades on funktsionaalse programmeerimise eesmärk kirjutada arusaadavam ja veakindlam kood. See saavutatakse, vältides voo juhtimise lausete (for
, while
, break
, continue
, goto
) kasutamist, mis muudavad koodi raskemini jälgitavaks. Samuti nõuab funktsionaalne programmeerimine puhta, deterministliku funktsiooni kirjutamist, mis on vähem tõenäoline, et lollakas on.
Selles artiklis räägime funktsionaalse programmeerimise tegemisest JavaScripti abil. Uurime ka erinevaid JavaScripti meetodeid ja funktsioone, mis seda võimaldavad. Lõpuks uurime funktsionaalse programmeerimisega seotud erinevaid mõisteid ja vaatame, miks need nii võimsad on.
Enne funktsionaalsesse programmeerimisse asumist tuleb siiski mõista puhaste ja ebapuhaste funktsioonide erinevust.
Puhtad funktsioonid vajavad teatud sisendit ja annavad kindla väljundi. Samuti ei põhjusta need välismaailmas kõrvaltoimeid.
const add = (a, b) => a + b;
Siin, add
on puhas funktsioon. Selle põhjuseks on fikseeritud väärtuse a
ja b
, väljund on alati sama.
const SECRET = 42; const getId = (a) => SECRET * a;
getId
ei ole puhas funktsioon. Põhjus on selles, et ta kasutab globaalset muutujat SECRET
väljundi arvutamiseks. Kui SECRET
pidid muutuma, getId
funktsioon tagastab sama sisendi jaoks teise väärtuse. Seega pole see puhas funktsioon.
let id_count = 0; const getId = () => ++id_count;
See on ka ebapuhas funktsioon ja ka paaril põhjusel - (1) kasutab see väljundi arvutamiseks mitte-lokaalset muutujat ja (2) tekitab kõrvalmõju, muutes selles muutujat. maailmas.
See võib olla tülikas, kui peaksime selle koodi siluma.
Mis on id_count
praegune väärtus? Milliseid funktsioone muudavad id_count
? Kas on muid funktsioone, millele toetub id_count
?
Nende põhjuste tõttu kasutame funktsionaalses programmeerimises ainult puhtaid funktsioone.
Puhaste funktsioonide eeliseks on ka see, et neid saab paralleelselt muuta ja üles märkida. Heitke pilk kahele eelmisele funktsioonile. Neid on võimatu paralleelselt muuta ega memodeerida. See aitab luua esituskoodi.
Siiani oleme õppinud, et funktsionaalne programmeerimine sõltub vähestest reeglitest. Need on järgmised.
Nende tingimuste täitmisel võime öelda, et meie kood on toimiv.
JavaScriptil on juba mõned funktsioonid, mis võimaldavad funktsionaalset programmeerimist. Näide: String.prototüüp.viil , Array.protoype.filter , Massiiv.prototüüp.liitu .
Teiselt poolt, Array.prototype.for igale , Array.prototype.push on ebapuhtad funktsioonid.
Võib väita, et Array.prototype.forEach
ei ole disainilt ebapuhas funktsioon, kuid mõelge sellele - sellega pole võimalik midagi muud teha, kui muteerida kohalikke andmeid või teha kõrvaltoimeid. Seega on okei panna see ebapuhaste funktsioonide kategooriasse.
Samuti on JavaScripti a konst deklaratsioon, mis sobib ideaalselt funktsionaalseks programmeerimiseks, kuna me ei muuda andmeid.
Vaatame mõningaid JavaScripti antud puhtaid funktsioone (meetodeid).
Nagu nimigi ütleb, filtreerib see massiivi.
array.filter(condition);
Tingimus on siin funktsioon, mis saab massiivi iga elemendi, ja see peaks otsustama, kas jätta üksus alles või mitte, ning tagastama selle jaoks tõese tõeväärtuse väärtuse.
const filterEven = x => x%2 === 0; [1, 2, 3].filter(filterEven); // [2]
Pange tähele, et filterEven
on puhas funktsioon. Kui see oleks olnud ebapuhas, oleks see kogu filtri kõne ebapuhtaks teinud.
map
kaardistab iga massiiviüksuse funktsiooniks ja loob funktsiooni väljakutse tagasiväärtuste põhjal uue massiivi.
array.map(mapper)
mapper
on funktsioon, mis võtab massiivi üksuse sisendiks ja tagastab väljundi.
const double = x => 2 * x; [1, 2, 3].map(double); // [2, 4, 6]
reduce
vähendab massiivi ühele väärtusele.
array.reduce(reducer);
reducer
on funktsioon, mis võtab massiivi kogunenud väärtuse ja järgmise üksuse ning tagastab uue väärtuse. Seda nimetatakse kõigi massiivi väärtuste jaoks üksteise järel.
const sum = (accumulatedSum, arrayItem) => accumulatedSum + arrayItem [1, 2, 3].reduce(sum); // 6
concat
lisab uue massiivi loomiseks olemasolevale massiivile uusi üksusi. See erineb push()
-st selles mõttes, et push()
muteerib andmeid, mis muudab need ebapuhasteks.
[1, 2].concat([3, 4]) // [1, 2, 3, 4]
Sama saate teha ka kasutades levik operaator.
[1, 2, ...[3, 4]]
Object.assign
kopeerib pakutava objekti väärtused uuele objektile. Kuna funktsionaalne programmeerimine põhineb muutumatutel andmetel, kasutame seda uute objektide valmistamiseks olemasolevate objektide põhjal.
const obj = {a : 2}; const newObj = Object.assign({}, obj); newObj.a = 3; obj.a; // 2
Aasta tulekuga ES6 , seda saab teha ka hajutusoperaatori abil.
const newObj = {...obj};
Saame luua ka oma puhta funktsiooni. Teeme ühe stringi dubleerimiseks n
kordade arv.
const duplicate = (str, n) => n <1 ? '' : str + duplicate(str, n-1);
See funktsioon dubleerib stringi n
korda ja tagastab uue stringi.
duplicate('hooray!', 3) // hooray!hooray!hooray!
Kõrgema järgu funktsioonid on funktsioonid, mis aktsepteerivad funktsiooni argumendina ja tagastavad funktsiooni. Sageli kasutatakse neid funktsiooni funktsionaalsuse täiendamiseks.
const withLog = (fn) => { return (...args) => { console.log(`calling ${fn.name}`); return fn(...args); }; };
Ülaltoodud näites loome withLog
kõrgemat järku funktsioon, mis võtab funktsiooni ja tagastab funktsiooni, mis logib sõnumi enne pakitud funktsiooni käivitamist.
const add = (a, b) => a + b; const addWithLogging = withLog(add); addWithLogging(3, 4); // calling add // 7
withLog
HOF-i saab kasutada ka teiste funktsioonidega ning see töötab ilma konfliktide ja lisakoodi kirjutamiseta. See on HOF-i ilu.
const addWithLogging = withLog(add); const hype = s => s + '!!!'; const hypeWithLogging = withLog(hype); hypeWithLogging('Sale'); // calling hype // Sale!!!
Seda võib nimetada ka ilma kombineerimisfunktsiooni määratlemata.
withLog(hype)('Sale'); // calling hype // Sale!!!
Karrierimine tähendab funktsiooni lagundamist, mis võtab mitu argumenti ühte või mitmesse kõrgemat järku funktsioonide tasemesse.
Võtame add
funktsioon.
const add = (a, b) => a + b;
Kui peaksime seda karri tegema, kirjutame selle ümber, jaotades argumendid mitmele tasandile järgmiselt.
const add = a => { return b => { return a + b; }; }; add(3)(4); // 7
Karrierimise eeliseks on memode lisamine. Nüüd saame funktsioonikõnes teatud argumendid meelde jätta, et neid saaks hiljem uuesti kasutada ilma dubleerimise ja ümberarvutamiseta.
// assume getOffsetNumer() call is expensive const addOffset = add(getOffsetNumber()); addOffset(4); // 4 + getOffsetNumber() addOffset(6);
See on kindlasti parem kui mõlema argumendi kasutamine kõikjal.
// (X) DON'T DO THIS add(4, getOffsetNumber()); add(6, getOffsetNumber()); add(10, getOffsetNumber());
Saame ka oma karrifunktsiooni lühikese väljanägemisega ümber vormindada. Selle põhjuseks on asjaolu, et karrifunktsioonikõne iga tase on ühe rea tagastamise lause. Seetõttu saame kasutada noole funktsioonid ES6-s, et seda ümber ehitada järgmiselt.
const add = a => b => a + b;
Matemaatikas on kompositsioon määratletud kui ühe funktsiooni väljundi edastamine teise sisendisse, et luua kombineeritud väljund. Sama on võimalik funktsionaalses programmeerimises, kuna kasutame puhtaid funktsioone.
Näite näitamiseks looge mõned funktsioonid.
Esimene funktsioon on vahemik, mis võtab algusnumbri a
ja lõpunumber b
ja loob massiivi, mis koosneb numbritest a
kuni b
.
const range = (a, b) => a > b ? [] : [a, ...range(a+1, b)];
Siis on meil funktsiooni korrutis, mis võtab massiivi ja korrutab selles kõik arvud.
const multiply = arr => arr.reduce((p, a) => p * a);
Faktoori arvutamiseks kasutame neid funktsioone koos.
const factorial = n => multiply(range(1, n)); factorial(5); // 120 factorial(6); // 720
Eeltoodud faktoriaalarvutamise funktsioon on sarnane f(x) = g(h(x))
-ga, demonstreerides seega kompositsiooni omadust.
Läksime läbi puhtad ja ebapuhased funktsioonid, funktsionaalne programmeerimine, uued JavaScripti funktsioonid, mis seda aitavad, ja mõned funktsionaalse programmeerimise põhimõisted.
Loodame, et see tükk äratab teie huvi funktsionaalse programmeerimise vastu ja võib-olla motiveerib teid seda oma koodis proovima. Oleme kindlad, et see on õppekogemus ja verstapost teie tarkvaraarenduse teekonnal.
Funktsionaalne programmeerimine on a hästi - uuritud ja jõuline arvutiprogrammide kirjutamise paradigma. Koos ES6 kasutuselevõtt , JavaScript võimaldab palju paremat funktsionaalset programmeerimiskogemust kui kunagi varem.
Funktsionaalne programmeerimine on deklaratsioonide ja avaldiste abil arvutiprogrammide loomise paradigma.
Tänu ES6 uutele arengutele võime öelda, et JavaScript on nii funktsionaalne kui ka objektorienteeritud programmeerimiskeel, kuna see pakub erinevaid esmaklassilisi funktsioone.
Funktsionaalne programmeerimine tagab lihtsama voo juhtimise meie koodis ja väldib üllatusi muutuja ja oleku muutuste näol. Kõik see aitab meil vältida vigu ja mõista meie koodi hõlpsalt.
Lisp, Erlang, Haskell, Closure ja Python on muud funktsionaalsed programmeerimiskeeled. Nendes on Haskell puhtalt funktsionaalne programmeerimiskeel selles mõttes, et see ei võimalda ühtegi muud programmeerimisparadigmat.
ES6 või ECMAScript 6 on JavaScripti uus versioon, mis sisaldab paljude teiste hulgas palju uusi funktsioone, nagu noole funktsioonid, konstandid ja hajutusoperaatorid.