Vabastage JavaScripti massiivide funktsionaalse programmeerimise jõud. Õppige oma andmeid tõhusalt teisendama, filtreerima ja vähendama sisseehitatud meetodite abil.
JavaScripti massiivide funktsionaalse programmeerimise meisterdamine
Veebiarenduse pidevalt arenevas maastikus on JavaScript jätkuvalt nurgakivi. Kuigi objektorienteeritud ja käskiv programmeerimisparadigma on pikka aega domineerinud, on funktsionaalne programmeerimine (FP) saavutanud märkimisväärse tõmbejõu. FP rõhutab muutumatust, puhtaid funktsioone ja deklaratiivset koodi, mis viib robustsemate, hooldatavamate ja prognoositavamate rakendusteni. Üks võimsamaid viise funktsionaalse programmeerimise omaksvõtmiseks JavaScriptis on selle natiivsete massiivi meetodite kasutamine.
See põhjalik juhend sukeldub sellesse, kuidas saate JavaScripti massiivide abil rakendada funktsionaalse programmeerimise põhimõtteid. Uurime peamisi kontseptsioone ja näitame, kuidas neid rakendada, kasutades selliseid meetodeid nagu map
, filter
ja reduce
, muutes teie andmete manipuleerimise viisi.
Mis on funktsionaalne programmeerimine?
Enne JavaScripti massiividesse sukeldumist määratleme lühidalt funktsionaalse programmeerimise. Oma olemuselt on FP programmeerimisparadigma, mis käsitleb arvutamist matemaatiliste funktsioonide hindamisena ning väldib oleku ja muudetavate andmete muutmist. Peamised põhimõtted hõlmavad:
- Puhtad funktsioonid: Puhas funktsioon annab alati sama väljundi sama sisendi korral ja sellel pole kõrvalmõjusid (see ei muuda välist olekut).
- Muutumatus: Andmeid, kui need on loodud, ei saa muuta. Olemasolevate andmete muutmise asemel luuakse soovitud muudatustega uued andmed.
- Esimese klassi funktsioonid: Funktsioone saab käsitleda nagu iga teist muutujat – neid saab määrata muutujatele, edastada argumentidena teistele funktsioonidele ja tagastada funktsioonidena.
- Deklaratiivne vs. käskiv: Funktsionaalne programmeerimine kaldub deklaratiivse stiili poole, kus kirjeldate, mida soovite saavutada, mitte käskiva stiili poole, mis kirjeldab samm-sammult, kuidas seda saavutada.
Nende põhimõtete omaksvõtmine võib viia koodini, mida on lihtsam mõista, testida ja siluda, eriti keerukates rakendustes. JavaScripti massiivide meetodid sobivad nende kontseptsioonide rakendamiseks suurepäraselt.
JavaScripti massiivide meetodite jõud
JavaScripti massiivid on varustatud rikkaliku sisseehitatud meetodite komplektiga, mis võimaldavad keerukat andmete manipuleerimist ilma traditsiooniliste tsükliteta (nagu for
või while
). Need meetodid tagastavad sageli uued massiivid, edendades muutumatust, ja aktsepteerivad tagasikutsumisfunktsioone, võimaldades funktsionaalset lähenemist.
Uurime kõige fundamentaalsemaid funktsionaalseid massiivi meetodeid:
1. Array.prototype.map()
map()
meetod loob uue massiivi, mis on täidetud kõigile kutsutud massiivi elementidele rakendatud funktsiooni tulemustega. See sobib ideaalselt iga massiivi elemendi teisendamiseks millekski uueks.
Süntaks:
array.map(callback(currentValue[, index[, array]])[, thisArg])
callback
: iga elemendi jaoks täidetav funktsioon.currentValue
: massiivis praegu töödeldav element.index
(valikuline): töödeldava elemendi indeks.array
(valikuline): massiiv, millelemap
kutsuti.thisArg
(valikuline): väärtus, mida kasutadathis
-nacallback
-i täitmisel.
Peamised omadused:
- Tagastab uue massiivi.
- Originaalmassiiv jääb muutmata (muutumatus).
- Uus massiiv on sama pikkusega kui originaalmassiiv.
- Tagasikutsumisfunktsioon peaks tagastama iga elemendi teisendatud väärtuse.
Näide: iga numbri kahekordistamine
Kujutage ette, et teil on numbrite massiiv ja soovite luua uue massiivi, kus iga number on kahekordistatud.
const numbers = [1, 2, 3, 4, 5];
// Kasutades teisendamiseks map
const doubledNumbers = numbers.map(number => number * 2);
console.log(numbers); // Väljund: [1, 2, 3, 4, 5] (originaalmassiiv jääb muutmata)
console.log(doubledNumbers); // Väljund: [2, 4, 6, 8, 10]
Näide: objektidest atribuutide väljavõtmine
Tavaline kasutusjuht on konkreetsete atribuutide väljavõtmine objektide massiivist. Oletame, et meil on kasutajate loend ja tahame saada ainult nende nimesid.
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
];
const userNames = users.map(user => user.name);
console.log(userNames); // Väljund: ['Alice', 'Bob', 'Charlie']
2. Array.prototype.filter()
filter()
meetod loob uue massiivi kõigi elementidega, mis läbivad antud funktsiooni abil antud testi. Seda kasutatakse elementide valimiseks tingimuse alusel.
Süntaks:
array.filter(callback(element[, index[, array]])[, thisArg])
callback
: iga elemendi jaoks täidetav funktsioon. See peaks tagastamatrue
, et säilitada element, võifalse
, et see kõrvaldada.element
: massiivis praegu töödeldav element.index
(valikuline): praeguse elemendi indeks.array
(valikuline): massiiv, millelefilter
kutsuti.thisArg
(valikuline): väärtus, mida kasutadathis
-nacallback
-i täitmisel.
Peamised omadused:
- Tagastab uue massiivi.
- Originaalmassiiv jääb muutmata (muutumatus).
- Uus massiiv võib olla väiksem kui originaalmassiiv.
- Tagasikutsumisfunktsioon peab tagastama boolean väärtuse.
Näide: paaritute numbrite filtreerimine
Filtreerime numbrite massiivi, et säilitada ainult paaritud numbrid.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Kasutades filtreerimist paaritute numbrite valimiseks
const evenNumbers = numbers.filter(number => number % 2 === 0);
console.log(numbers); // Väljund: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(evenNumbers); // Väljund: [2, 4, 6, 8, 10]
Näide: aktiivsete kasutajate filtreerimine
Meie kasutajate massiivist filtreerime kasutajad, kes on märgitud aktiivseteks.
const users = [
{ id: 1, name: 'Alice', isActive: true },
{ id: 2, name: 'Bob', isActive: false },
{ id: 3, name: 'Charlie', isActive: true },
{ id: 4, name: 'David', isActive: false }
];
const activeUsers = users.filter(user => user.isActive);
console.log(activeUsers);
/* Väljund:
[
{ id: 1, name: 'Alice', isActive: true },
{ id: 3, name: 'Charlie', isActive: true }
]
*/
3. Array.prototype.reduce()
reduce()
meetod täidab kasutaja poolt pakutud "reduktori" tagasikutsumisfunktsiooni iga massiivi elemendi kohta järjest, edastades eelmisel elemendil arvutamise tulemuse. Reduktori kogu massiivi elementide kaudu käitamise lõpptulemus on üks väärtus.
See on vaieldamatult kõige mitmekülgsem massiivi meetoditest ja paljude funktsionaalse programmeerimise mustrite alustala, mis võimaldab teil massiivi "vähendada" üheks väärtuseks (nt summa, korrutis, loendus või isegi uus objekt või massiiv).
Süntaks:
array.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
callback
: iga elemendi jaoks täidetav funktsioon.accumulator
: eelmisel tagasikutsumisfunktsiooni kõnel saadud tulemus. Esimesel kõnel on seeinitialValue
, kui see on esitatud; vastasel juhul on see massiivi esimene element.currentValue
: praegu töödeldav element.index
(valikuline): praeguse elemendi indeks.array
(valikuline): massiiv, millelereduce
kutsuti.initialValue
(valikuline): väärtus, mida kasutadacallback
-i esimesel kõnel esimese argumendina. KuiinitialValue
ei ole antud, kasutatakse massiivi esimest elementi esialgseaccumulator
väärtusena ja itereerimine algab teisest elemendist.
Peamised omadused:
- Tagastab ühe väärtuse (mis võib olla ka massiiv või objekt).
- Originaalmassiiv jääb muutmata (muutumatus).
initialValue
on selguse ja vigade vältimise jaoks ülioluline, eriti tühjade massiivide korral või kui akumulaatori tüüp erineb massiivi elemendi tüübist.
Näide: numbrite summeerimine
Summeerime kõik numbrid meie massiivis.
const numbers = [1, 2, 3, 4, 5];
// Kasutades summeerimiseks reduce
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0); // 0 on initialValue
console.log(sum); // Väljund: 15
Selgitus:
- 1. kõne:
accumulator
on 0,currentValue
on 1. Tagastab 0 + 1 = 1. - 2. kõne:
accumulator
on 1,currentValue
on 2. Tagastab 1 + 2 = 3. - 3. kõne:
accumulator
on 3,currentValue
on 3. Tagastab 3 + 3 = 6. - Ja nii edasi, kuni lõppsumma on arvutatud.
Näide: objektide grupeerimine atribuudi järgi
Võime kasutada reduce
-i objektide massiivi teisendamiseks objektiks, kus väärtused on grupeeritud konkreetse atribuudi järgi. Grupeerime oma kasutajad nende isActive
oleku järgi.
const users = [
{ id: 1, name: 'Alice', isActive: true },
{ id: 2, name: 'Bob', isActive: false },
{ id: 3, name: 'Charlie', isActive: true },
{ id: 4, name: 'David', isActive: false }
];
const groupedUsers = users.reduce((acc, user) => {
const status = user.isActive ? 'active' : 'inactive';
if (!acc[status]) {
acc[status] = [];
}
acc[status].push(user);
return acc;
}, {}); // Tühi objekt {} on initialValue
console.log(groupedUsers);
/* Väljund:
{
active: [
{ id: 1, name: 'Alice', isActive: true },
{ id: 3, name: 'Charlie', isActive: true }
],
inactive: [
{ id: 2, name: 'Bob', isActive: false },
{ id: 4, name: 'David', isActive: false }
]
}
*/
Näide: esinemiste arvestamine
Arvutame iga puuvilja esinemissageduse loendis.
const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
const fruitCounts = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {});
console.log(fruitCounts); // Väljund: { apple: 3, banana: 2, orange: 1 }
4. Array.prototype.forEach()
Kuigi forEach()
ei tagasta uut massiivi ja seda peetakse sageli käskivamaks, kuna selle peamine eesmärk on funktsiooni täitmine iga massiivi elemendi jaoks, on see siiski fundamentaalne meetod, mis mängib rolli funktsionaalsetes mustrites, eriti kui kõrvalmõjud on vajalikud või kui itereeritakse ilma teisendatud väljundit vajamata.
Süntaks:
array.forEach(callback(element[, index[, array]])[, thisArg])
Peamised omadused:
- Tagastab
undefined
. - Täidab antud funktsiooni üks kord iga massiivi elemendi kohta.
- Kasutatakse sageli kõrvalmõjude jaoks, näiteks konsoolile logimiseks või DOM-elementide värskendamiseks.
Näide: iga elemendi logimine
const messages = ['Hello', 'Functional', 'World'];
messages.forEach(message => console.log(message));
// Väljund:
// Hello
// Functional
// World
Märkus: Teisenduste ja filtreerimise jaoks on map
ja filter
eelistatud nende muutumatuse ja deklaratiivsuse tõttu. Kasutage forEach
-i, kui peate konkreetse toimingu tegemiseks iga üksuse jaoks, ilma et tulemusi uude struktuuri koguksite.
5. Array.prototype.find()
ja Array.prototype.findIndex()
Need meetodid on kasulikud konkreetsete elementide leidmiseks massiivist.
find()
: Tagastab antud testifunktsiooni rahuldava esimese massiivi elemendi väärtuse. Kui ükski väärtus ei vasta testifunktsioonile, tagastatakseundefined
.findIndex()
: Tagastab antud testifunktsiooni rahuldava esimese massiivi elemendi indeksi. Vastasel juhul tagastab see -1, mis näitab, et ükski element ei läbinud testi.
Näide: kasutaja leidmine
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
];
const bob = users.find(user => user.name === 'Bob');
const bobIndex = users.findIndex(user => user.name === 'Bob');
const nonExistentUser = users.find(user => user.name === 'David');
const nonExistentIndex = users.findIndex(user => user.name === 'David');
console.log(bob); // Väljund: { id: 2, name: 'Bob' }
console.log(bobIndex); // Väljund: 1
console.log(nonExistentUser); // Väljund: undefined
console.log(nonExistentIndex); // Väljund: -1
6. Array.prototype.some()
ja Array.prototype.every()
Need meetodid testivad, kas kõik massiivi elemendid läbivad antud funktsiooni abil antud testi.
some()
: Testib, kas vähemalt üks massiivi element läbib antud funktsiooni abil antud testi. See tagastab boolean väärtuse.every()
: Testib, kas kõik massiivi elemendid läbivad antud funktsiooni abil antud testi. See tagastab boolean väärtuse.
Näide: kasutaja oleku kontrollimine
const users = [
{ id: 1, name: 'Alice', isActive: true },
{ id: 2, name: 'Bob', isActive: false },
{ id: 3, name: 'Charlie', isActive: true }
];
const hasInactiveUser = users.some(user => !user.isActive);
const allAreActive = users.every(user => user.isActive);
console.log(hasInactiveUser); // Väljund: true (kuna Bob on passiivne)
console.log(allAreActive); // Väljund: false (kuna Bob on passiivne)
const allUsersActive = users.filter(user => user.isActive).length === users.length;
console.log(allUsersActive); // Väljund: false
// Alternatiiv igaühe otse kasutamise kaudu
const allUsersActiveDirect = users.every(user => user.isActive);
console.log(allUsersActiveDirect); // Väljund: false
Massiivide meetodite ühendamine keerukate toimingute jaoks
Funktsionaalse programmeerimise tõeline jõud JavaScripti massiividega avaldub siis, kui ühendate need meetodid. Kuna enamik neist meetoditest tagastab uued massiivid (välja arvatud forEach
), saate ühe meetodi väljundi sujuvalt järgmise sisendiks juhtida, luues elegantseid ja loetavaid andmepipeliine.
Näide: aktiivsete kasutajate nimede leidmine ja nende ID-de kahekordistamine
Leiame kõik aktiivsed kasutajad, võtame välja nende nimed ja loome seejärel uue massiivi, kus iga nimi on eesliitega nummerdatud, mis tähistab selle indekseid filtreeritud loendis, ja nende ID-d on kahekordistatud.
const users = [
{ id: 1, name: 'Alice', isActive: true },
{ id: 2, name: 'Bob', isActive: false },
{ id: 3, name: 'Charlie', isActive: true },
{ id: 4, name: 'David', isActive: true },
{ id: 5, name: 'Eve', isActive: false }
];
const processedActiveUsers = users
.filter(user => user.isActive) // Hankige ainult aktiivsed kasutajad
.map((user, index) => ({ // Teisendage iga aktiivne kasutaja
name: `${index + 1}. ${user.name}`,
doubledId: user.id * 2
}));
console.log(processedActiveUsers);
/* Väljund:
[
{ name: '1. Alice', doubledId: 2 },
{ name: '2. Charlie', doubledId: 6 },
{ name: '3. David', doubledId: 8 }
]
*/
See ühendatud lähenemine on deklaratiivne: me määrate sammud (esmalt filtreerimine, seejärel map) ilma selge tsüklihalduse ta. See on ka muutumatu, kuna iga samm loob uue massiivi või objekti, jättes originaal users
massiivi puutumata.
Muutumatus praktikas
Funktsionaalne programmeerimine tugineb suuresti muutumatusele. See tähendab, et olemasolevate andmestruktuuride muutmise asemel loote soovitud muudatustega uued. JavaScripti massiivide meetodid, nagu map
, filter
ja slice
, toetavad seda sisemiselt, tagastades uued massiivid.
Miks on muutumatus oluline?
- Prognoositavus: Koodi muutub lihtsamaks mõista, sest te ei pea jälgima jagatud muudetava oleku muutusi.
- Silumine: Kui tekivad vead, on andmete ootamatu muutumise korral lihtsam probleemi allikat tuvastada.
- Jõudlus: Teatud kontekstides (nagu Redux või Reacti olekuhaldusraamatukogude puhul) võimaldab muutumatus tõhusat muutuste tuvastamist.
- Kaasutus: Muutumatud andmestruktuurid on sisemiselt niiditurbed, mis lihtsustab kaasjuhtimisprogrammeerimist.
Kui peate tegema toimingu, mis traditsiooniliselt muudaks massiivi (nt elemendi lisamine või eemaldamine), saate muutumatust saavutada, kasutades selliseid meetodeid nagu slice
, levitamissüntaks (...
) või teiste funktsionaalsete meetodite kombineerimisel.
Näide: elemendi muutumatu lisamine
const originalArray = [1, 2, 3];
// Käskiv viis (muudab originalArray)
// originalArray.push(4);
// Funktsionaalne viis levitamissüntaksi abil
const newArrayWithPush = [...originalArray, 4];
console.log(originalArray); // Väljund: [1, 2, 3]
console.log(newArrayWithPush); // Väljund: [1, 2, 3, 4]
// Funktsionaalne viis, kasutades slice ja ühendamist (praegu vähem levinud)
const newArrayWithSlice = originalArray.slice(0, originalArray.length).concat(4);
console.log(newArrayWithSlice); // Väljund: [1, 2, 3, 4]
Näide: elemendi muutumatu eemaldamine
const originalArray = [1, 2, 3, 4, 5];
// Elemendi eemaldamine indeksil 2 (väärtus 3)
// Funktsionaalne viis, kasutades slice ja levitamissüntaksit
const newArrayAfterSplice = [
...originalArray.slice(0, 2),
...originalArray.slice(3)
];
console.log(originalArray); // Väljund: [1, 2, 3, 4, 5]
console.log(newArrayAfterSplice); // Väljund: [1, 2, 4, 5]
// Filtri kasutamine konkreetse väärtuse eemaldamiseks
const newValueToRemove = 3;
const arrayWithoutValue = originalArray.filter(item => item !== newValueToRemove);
console.log(arrayWithoutValue); // Väljund: [1, 2, 4, 5]
Parimad praktikad ja täiustatud tehnikad
Kui muutute funktsionaalsete massiivi meetoditega mugavamaks, kaaluge neid tavasid:
- Esmalt loetavus: Kuigi ühendamine on võimas, võivad liiga pikad ahelad muutuda raskesti loetavaks. Kaaluge keerukate toimingute jagamist väiksemateks, nimetatud funktsioonideks või vahepealsete muutujate kasutamist.
- Mõistke
reduce
paindlikkust: Pidage meeles, etreduce
võib koostada massiive või objekte, mitte ainult üksikuid väärtusi. See muudab selle keerukate teisenduste jaoks uskumatult mitmekülgseks. - Vältige tagasikutsumisfunktsioonides kõrvalmõjusid: Püüdke hoida oma
map
,filter
jareduce
tagasikutsumisfunktsioonid puhtana. Kui peate tegema kõrvalmõjuga toimingu, onforEach
sageli sobivam valik. - Kasutage noolfunktsioone: Noolfunktsioonid (
=>
) pakuvad tagasikutsumisfunktsioonide jaoks lühikest süntaksit ja käsitlevadthis
sidumist erinevalt, muutes need sageli ideaalseks funktsionaalsete massiivi meetodite jaoks. - Kaaluge raamatukogusid: keerukamate funktsionaalsete programmeerimis mustrite jaoks või kui töötate ulatuslikult muutumatusega, võivad sellised raamatukogud nagu Lodash/fp, Ramda või Immutable.js olla kasulikud, kuigi need pole tänapäeva JavaScripti funktsionaalsete massiivi toimingute alustamiseks rangelt vajalikud.
Näide: funktsionaalne lähenemine andmete koondamisele
Kujutage ette, et teil on erinevate piirkondade müügiandmed ja soovite arvutada iga piirkonna kogumüügi, seejärel leida piirkonna, kus on suurim müük.
const salesData = [
{ region: 'North', amount: 100 },
{ region: 'South', amount: 150 },
{ region: 'North', amount: 120 },
{ region: 'East', amount: 200 },
{ region: 'South', amount: 180 },
{ region: 'North', amount: 90 }
];
// 1. Arvutage kogumüük piirkonna kohta, kasutades reduce
const salesByRegion = salesData.reduce((acc, sale) => {
acc[sale.region] = (acc[sale.region] || 0) + sale.amount;
return acc;
}, {});
// salesByRegion saab olema: { North: 310, South: 330, East: 200 }
// 2. teisendage koondatud objekt edasiseks töötlemiseks objektide massiiviks
const salesArray = Object.keys(salesByRegion).map(region => ({
region: region,
totalAmount: salesByRegion[region]
}));
// salesArray saab olema: [
// { region: 'North', totalAmount: 310 },
// { region: 'South', totalAmount: 330 },
// { region: 'East', totalAmount: 200 }
// ]
// 3. Leidke reduce abil piirkond suurima müügiga
const highestSalesRegion = salesArray.reduce((max, current) => {
return current.totalAmount > max.totalAmount ? current : max;
}, { region: '', totalAmount: -Infinity }); // Alustage väga väikese numbriga
console.log('Sales by Region:', salesByRegion);
console.log('Sales Array:', salesArray);
console.log('Region with Highest Sales:', highestSalesRegion);
/*
Väljund:
Sales by Region: { North: 310, South: 330, East: 200 }
Sales Array: [
{ region: 'North', totalAmount: 310 },
{ region: 'South', totalAmount: 330 },
{ region: 'East', totalAmount: 200 }
]
Region with Highest Sales: { region: 'South', totalAmount: 330 }
*/
Järeldus
Funktsionaalne programmeerimine JavaScripti massiividega ei ole lihtsalt stiilivalik; see on võimas viis puhtama, prognoositavama ja robustsema koodi kirjutamiseks. Võttes kasutusele sellised meetodid nagu map
, filter
ja reduce
, saate oma andmeid tõhusalt teisendada, päringuid teha ja koondada, järgides samal ajal funktsionaalse programmeerimise põhiprintsiipe, eriti muutumatust ja puhtaid funktsioone.
Jätkates oma JavaScripti arendamise teekonda, integreerides need funktsionaalsed mustrid oma igapäevasesse töövoogu, toob kahtlemata kaasa hooldatavamad ja skaleeritavamad rakendused. Alustage nende massiivi meetoditega oma projektides eksperimenteerimist ja avastate peagi nende tohutu väärtuse.