Funkcinis programavimas „JavaScript“ kalba paaiškinamas paprastąja anglų kalba

Vienas sunkiausių dalykų, kurį turite atlikti programuodami, yra kontrolės sudėtingumas. Kruopščiai neapgalvojus, programos dydis ir sudėtingumas gali išaugti taip, kad suklaidintų net programos kūrėją.

Tiesą sakant, kaip teigė vienas autorius:

„Programavimo menas yra įgūdis kontroliuoti sudėtingumą“ - Marijn Haverbeke

Šiame straipsnyje mes suskirstysime pagrindinę programavimo koncepciją. Ši programavimo koncepcija gali padėti kontroliuoti sudėtingumą ir rašyti geresnes programas.

Šio straipsnio pabaigoje jūs sužinosite, kas yra funkcinis programavimas, kokių funkcijų tipai yra, funkcinio programavimo principai ir giliau suprasite aukštesnės tvarkos funkcijas.

Manau, kad jūs jau turite išankstinių žinių apie funkcijų pagrindus. Pagrindinės funkcijų sąvokos šiame straipsnyje nebus nagrinėjamos.

Jei norite greitai peržiūrėti „JavaScript“ funkcijas, aš čia parašiau išsamų straipsnį.

Kas yra funkcinis programavimas?

Funkcinis programavimas yra programavimo paradigma arba programavimo stilius, kuris labai priklauso nuo grynų ir izoliuotų funkcijų naudojimo.

Kaip spėjote iš pavadinimo, funkcijų naudojimas yra pagrindinis funkcinio programavimo komponentas. Tačiau vien funkcijų naudojimas nereiškia funkcinio programavimo.

Funkciniame programavime naudojame grynąsias funkcijas, kurios neturi šalutinio poveikio. Aš paaiškinsiu, ką visa tai reiškia.

Prieš gilindamiesi į straipsnį, leiskite mums suprasti kai kurias terminologijas ir funkcijų tipus.

Funkcijų tipai

Yra keturi pagrindiniai funkcijų tipai.

Pirmos klasės funkcijos

„JavaScript“ visos funkcijos yra pirmos klasės funkcijos. Tai reiškia, kad su jais galima elgtis kaip su bet kuriuo kitu kintamuoju.

Pirmos klasės funkcijos yra funkcijos, kurias galima priskirti kintamiesiems kaip reikšmes, grąžinti iš kitų funkcijų ir perduoti kaip argumentus į kitas funkcijas.

Apsvarstykite šį kintamajam perduotos funkcijos pavyzdį:

const helloWorld = () => { console.log("Hello, World"); // Hello, World }; helloWorld(); 

Skambinimo funkcijos

Grąžinimo funkcijos yra funkcijos, kurios perduodamos kitoms funkcijoms kaip argumentai ir kurias vadina funkcija, kurioje jos yra perduodamos.

Tiesiog skambinimo funkcijos yra funkcijos, kurias rašome kaip argumentus kitose funkcijose. Negalime pasinaudoti atgalinio skambinimo funkcijomis. Jie yra iškviečiami, kai iškviečiama pagrindinė funkcija, kurioje jie buvo perduodami kaip argumentai.

Pažvelkime į pavyzdį:

const testValue = (value, test) => { if (test(value)) { return `${value} passed the test`; } else return `${value} did not pass the test`; }; const checkString = testValue('Twitter', string => typeof string === 'string'); checkString; // Twitter passed the test 

testValueyra funkcija, kuri priima vertę ir atgalinio skambinimo funkciją, test  kuri pateikia „testą išlaikiusią vertę“, jei reikšmė grįžta į tikrąją, kai perduodama atgalinio ryšio funkcija.

Šiuo atveju atgalinio skambinimo funkcija yra antrasis argumentas, kurį perdavėme į testValuefunkciją. Jis iškviečiamas, kai iškviečiama testValuefunkcija.

Aukštesnio užsakymo funkcijos

Aukštesnės eilės funkcijos yra funkcijos, kurios gauna kitas funkcijas kaip argumentus arba grąžina funkciją.

Šiame straipsnyje aš išsamiau paaiškinsiu aukštesnės eilės funkcijas ir kodėl jos yra tokia galinga nuostata. Kol kas tereikia žinoti, kad tokio tipo funkcijos gauna kitas funkcijas kaip argumentus arba grąžinimo funkcijas.

Asinchroninės funkcijos

Asinchroninės funkcijos yra funkcijos, kurios neturi pavadinimo ir jų negalima pakartotinai naudoti. Šios funkcijos paprastai rašomos, kai mums reikia ką nors atlikti vieną kartą ir tik vienoje vietoje.

Puikus asinchroninės funkcijos pavyzdys yra tai, ką rašėme anksčiau straipsnyje.

const checkString = testValue('Twitter', value => typeof value === 'string'); checkString; // Refer to previous code snippet

checkStringyra kintamasis, kurio reikšmė yra funkcija. Į šią funkciją perduodame du argumentus.

'Twitter'yra pirmasis argumentas, o antrasis - asinchroninė funkcija. Ši funkcija neturi vieno pavadinimo ir turi tik vieną užduotį: patikrinti, ar nurodyta reikšmė yra eilutė.

Principai Meme

Funkcinio programavimo principai

Anksčiau straipsnyje užsiminiau, kad vien funkcijų naudojimas nereiškia funkcinio programavimo.

Yra keletas principų, kuriuos turime suprasti, kad mūsų programos atitiktų funkcinio programavimo standartą. Pažvelkime į tuos.

Venkite mutacijų ir šalutinių poveikių.

Pirmasis funkcinio programavimo principas yra vengti dalykų pakeitimo. Funkcija neturėtų pakeisti nieko, pavyzdžiui, visuotinio kintamojo.

Tai labai svarbu, nes dėl pokyčių dažnai atsiranda klaidų. Pavyzdžiui, jei funkcija pakeičia visuotinį kintamąjį, tai gali sukelti netikėtą elgesį visose vietose, kuriose tas kintamasis naudojamas.

Antrasis principas yra tas, kad funkcija turi būti gryna, vadinasi, ji neturi šalutinio poveikio. Funkciniame programavime atliekami pakeitimai vadinami mutacijomis, o rezultatai - šalutiniais.

Gryna funkcija neatlieka nė vieno iš šių dviejų. Gryna funkcija visada turės tą patį išėjimą tam pačiam įėjimui.

Jei funkcija priklauso nuo visuotinio kintamojo, tas kintamasis turėtų būti perduotas funkcijai kaip argumentas. Tai leidžia mums gauti tą patį išėjimą tam pačiam įėjimui.

Štai pavyzdys:

const legalAgeInTheUS = 21; const checkLegalStatus = (age, legalAge) => { return age >= legalAge ? 'Of legal age.' : 'Not of legal age.'; }; const johnStatus = checkLegalStatus(18, legalAgeInTheUS); johnStatus; // Not of legal age legalAgeInTheUS; // 21 

Abstrakcija

Abstrakcijos slepia detales ir leidžia mums kalbėti apie problemas aukštesniu lygiu, neaprašant visų problemos įgyvendinimo detalių.

Abstrakcijas naudojame visais beveik visais savo gyvenimo aspektais, ypač kalboje.

Pavyzdžiui, užuot sakęs „Aš keisiu pinigus į mašiną, į kurią įjungus ekraną bus rodomi judantys vaizdai su garsu“ , greičiausiai sakysite „Aš nusipirksiu televizorių“ .

Šiuo atveju pirkimas ir televizija yra abstrakcijos. Šios abstrakcijos formos žymiai palengvina kalbą ir sumažina tikimybę pasakyti neteisingą dalyką.

Bet jūs sutiksite su manimi, kad prieš vartodami abstrakčius terminus, pvz., „ Pirkti“, pirmiausia turite suprasti šio termino prasmę ir jo iškeltą problemą.

Funkcijos leidžia pasiekti kažką panašaus. Mes galime sukurti užduočių funkcijas, kurias greičiausiai kartosime vėl ir vėl. Funkcijos leidžia mums susikurti savo abstrakcijas.

Be savo abstrakcijų kūrimo, mums jau sukurtos kai kurios funkcijos abstrakčioms užduotims, kurias greičiausiai darysime ne kartą.

Taigi mes nagrinėsime kai kurias iš šių aukštesnės eilės funkcijų, kurios jau egzistuoja abstrakčioms pasikartojančioms užduotims.

Filtering Arrays

When working with data structures like arrays, we are most likely to find ourselves in a situation where we are only interested in certain items in the array.

To obtain these items we can easily create a function to do the task:

function filterArray(array, test) { const filteredArray = []; for (let item of array) { if (test(item)) { filteredArray.push(item); } } return filteredArray; }; const mixedArray = [1, true, null, "Hello", undefined, "World", false]; const onlyStrings = filterArray(mixedArray, item => typeof item === 'string'); onlyStrings; // ['Hello', 'World'] 

filterArray is a function that accepts an array and a callback function. It loops through the array and adds the items that pass the test in the callback function into an array called filteredArray.

Using this function we are able to filter an array and return items that we're interested in, such as in the case of mixedArray.

Imagine if we had 10 different programs and in each program we needed to filter an array. Sooner or later it would become extremely tiresome to rewrite the same function over and over again.

Luckily someone already thought about this. Arrays have a standard filter method. It returns a new array with the items in the array it receives that pass the test that we provide.

const mixedArray = [1, true, null, "Hello", undefined, "World", false]; const stringArray = mixedArray.filter(item => typeof item === 'string') stringArray; // ['Hello', 'World'] 

Using the standard filter method we were able to achieve the same results we did when we defined our own function in the previous example. So, the filter method is an abstraction of the first function we wrote.

Transforming Array Items With Map

Imagine another scenario where we have an array of items but we would like to perform a certain operation on all the items. We can write a function to do this for us:

function transformArray(array, test) { const transformedArray = []; for (let item of array) { transformedArray.push(test(item)); } return transformedArray; }; const ages = [12, 15, 21, 19, 32]; const doubleAges = transformArray(ages, age => age * 2); doubleAges; // [24, 30, 42, 38, 64]; 

Just like that we  have created a function that loops through any given array and transforms all the items in the array based on the callback function the we provide.

But again this would grow tedious if we had to rewrite the function in 20 different programs.

Again, someone thought about this for us, and luckily arrays have a standard method called map which does the same exact thing. It applies the callback function on all the items in the given array and then it returns a new array.

const ages = [12, 15, 21, 19, 32]; const doubleAges = ages.map(age => age * 2); doubleAges; // [24, 30, 42, 38, 64]; 

Reducing Arrays with Reduce

Here's another scenario: You have an array of numbers, but you would like to compute the sum of all these numbers and return it. Of course you can write a function to do this for you.

function reduceArray(array, test, start) { let sum = start; for (let item of array) { sum = test(sum, item) } return sum; } let numbers = [5, 10, 20]; let doubleNumbers = reduceArray(numbers, (a, b) => a + b, 0); doubleNumbers; // 35 

Similar to the previous examples we just looked at, arrays have a standard reduce method that has the same logic as the function we just wrote above.

The reduce method is used to reduce an array to a single value based on the callback function that we provide. It also takes an optional second argument which specifies where we want the operation in the callback to start from.

The callback function we provide in the reduce function has two parameters. The first parameter is the first item in the array by default. Otherwise it is the second argument we provide into the reduce method. The second parameter is the current item in the array.

let numbers = [5, 10, 20]; let doubleNumbers = numbers.reduce((a, b) => a + b, 10); doubleNumbers; // 45 //The above example uses the reduce method to add all the items in the array starting from 10.

Other Useful Array Methods

Array.some()

All arrays have the some method which accepts a callback function. It returns true if any element in the array passes the test given in the callback  function. Otherwise it returns false:

const numbers = [12, 34, 75, 23, 16, 63] console.log(numbers.some(item => item < 100)) // true

Array.every()

The every method is the opposite of the some method. It also accepts a callback function and returns true if all the items in the array pass the test given in the callback  function. Otherwise it returns false:

const numbers = [12, 34, 75, 23, 16, 63] console.log(numbers.every(item => item < 100)) // true

Array.concat()

The concat method, short for concatenate, is a standard array method that concatenates or joins two arrays and returns a new array:

const array1 = ['one', 'two', 'three']; const array2 = ['four', 'five', 'six']; const array3 = array1.concat(array2); array3; // [ 'one', 'two', 'three', 'four', 'five', 'six' ]

Array.slice()

The slice method is an array method which copies the items of an array from a given index and returns a new array with the copied items. The slice method accepts two arguments.

Pirmasis argumentas gauna indeksą, nuo kurio reikia pradėti kopijuoti. Antrasis argumentas gauna indeksą, iš kurio nebebus kopijuojama. Jis grąžina naują masyvą su nukopijuotais elementais nuo pradinio indekso (išskirtinis) iki galutinio indekso (imtinai).

Tačiau atkreipkite dėmesį, kad griežinėlių metodas nenaudoja nulinio indeksavimo. Taigi pirmojo masyvo elemento indeksas yra 1, o ne 0:

const numbers = [1,2,3,4,5,7,8]; console.log(theArray.slice(1, 4)); // [ 2, 3, 4 ] 

Išvada

Tikiuosi, kad jums patiko skaityti šį straipsnį ir tuo pačiu išmokote kažką naujo.

Yra daugybė masyvo ir eilutės metodų, kurių nepaminėjau straipsnyje. Jei norite, skirkite šiek tiek laiko atlikdami šių metodų tyrimus.

Jei norite susisiekti su manimi ar tiesiog pasisveikinti? nedarykite to per „Twitter“. Taip pat dalinuosi įdomiais patarimais ir ištekliais kūrėjams. ?