Atklājiet funkcionālās programmēšanas spēku ar JavaScript masīviem. Apgūstiet, kā efektīvi transformēt, filtrēt un samazināt datus, izmantojot iebūvētās metodes.
Funkcionālās programmēšanas apguve ar JavaScript masīviem
Tīmekļa izstrādes ainavā, kas nepārtraukti attīstās, JavaScript joprojām ir stūrakmens. Lai gan objektorientētās un imperatīvās programmēšanas paradigmas ilgu laiku ir dominējušas, funkcionālā programmēšana (FP) iegūst ievērojamu popularitāti. FP uzsver nemainību, tīras funkcijas un deklaratīvu kodu, tādējādi radot robustākas, vieglāk uzturamas un prognozējamākas lietojumprogrammas. Viens no spēcīgākajiem veidiem, kā ieviest funkcionālo programmēšanu JavaScript, ir izmantot tās vietējās masīvu metodes.
Šis visaptverošais ceļvedis aplūkos, kā izmantot funkcionālās programmēšanas principus, lietojot JavaScript masīvus. Mēs izpētīsim galvenās koncepcijas un demonstrēsim, kā tās pielietot, izmantojot tādas metodes kā map
, filter
un reduce
, mainot veidu, kā jūs apstrādājat datu manipulācijas.
Kas ir funkcionālā programmēšana?
Pirms iedziļināties JavaScript masīvos, īsi definēsim funkcionālo programmēšanu. Tās pamatā FP ir programmēšanas paradigma, kas aprēķinu uzskata par matemātisko funkciju novērtēšanu un izvairās no stāvokļa un mainīgu datu maiņas. Galvenie principi ietver:
- Tīras Funkcijas: Tīra funkcija vienmēr dod to pašu izvadi vienai un tai pašai ievadei, un tai nav blakusefektu (tā nemodificē ārējo stāvokli).
- Nemainība: Datus, kad tie ir izveidoti, nevar mainīt. Tā vietā, lai modificētu esošos datus, tiek izveidoti jauni dati ar vēlamajām izmaiņām.
- Pirmās klases Funkcijas: Funkcijas var apstrādāt tāpat kā jebkuru citu mainīgo – tās var piešķirt mainīgajiem, nodot kā argumentus citām funkcijām un atgriezt no funkcijām.
- Deklaratīvs vs. Imperatīvs: Funkcionālā programmēšana sliecas uz deklaratīvu stilu, kurā jūs aprakstāt ko vēlaties sasniegt, nevis imperatīvu stilu, kas detalizē kā to sasniegt soli pa solim.
Šo principu pieņemšana var novest pie koda, ko ir vieglāk analizēt, testēt un atkļūdot, īpaši sarežģītās lietojumprogrammās. JavaScript masīvu metodes ir lieliski piemērotas šo koncepciju ieviešanai.
JavaScript masīvu metožu spēks
JavaScript masīvi ir aprīkoti ar plašu iebūvētu metožu kopumu, kas ļauj veikt sarežģītas datu manipulācijas, neizmantojot tradicionālās cilpas (piemēram, for
vai while
). Šīs metodes bieži atgriež jaunus masīvus, veicinot nemainību, un pieņem atzvanīšanas funkcijas, nodrošinot funkcionālu pieeju.
Izpētīsim visfundamentālākās funkcionālās masīvu metodes:
1. Array.prototype.map()
Metode map()
izveido jaunu masīvu, kas aizpildīts ar rezultātiem, ko iegūst, izsaucot norādīto funkciju katram elementam izsaucošajā masīvā. Tā ir ideāli piemērota katra masīva elementa pārveidošanai par kaut ko jaunu.
Sintakse:
array.map(callback(currentValue[, index[, array]])[, thisArg])
callback
: Funkcija, kas jāizpilda katram elementam.currentValue
: Pašreizējais elements, kas tiek apstrādāts masīvā.index
(pēc izvēles): Pašreizējā apstrādājamā elementa indekss.array
(pēc izvēles): Masīvs, uz kura tika izsauktsmap
.thisArg
(pēc izvēles): Vērtība, kas jāizmanto kāthis
, izpildotcallback
.
Galvenās iezīmes:
- Atgriež jaunu masīvu.
- Oriģinālais masīvs paliek nemainīgs (nemainība).
- Jaunajam masīvam būs tāds pats garums kā oriģinālajam masīvam.
- Atzvanīšanas funkcijai katram elementam jāatgriež transformētā vērtība.
Piemērs: Katra skaitļa dubultošana
Iedomājieties, ka jums ir skaitļu masīvs un vēlaties izveidot jaunu masīvu, kurā katrs skaitlis ir dubultots.
const numbers = [1, 2, 3, 4, 5];
// Izmantojot map transformācijai
const doubledNumbers = numbers.map(number => number * 2);
console.log(numbers); // Izvade: [1, 2, 3, 4, 5] (oriģinālais masīvs ir nemainīgs)
console.log(doubledNumbers); // Izvade: [2, 4, 6, 8, 10]
Piemērs: Īpašību izgūšana no objektiem
Bieži sastopams lietošanas gadījums ir specifisku īpašību izgūšana no objektu masīva. Pieņemsim, ka mums ir lietotāju saraksts un vēlamies iegūt tikai viņu vārdus.
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 3, name: 'Charlie' }
];
const userNames = users.map(user => user.name);
console.log(userNames); // Izvade: ['Alice', 'Bob', 'Charlie']
2. Array.prototype.filter()
Metode filter()
izveido jaunu masīvu ar visiem elementiem, kas iztur pārbaudi, ko veic norādītā funkcija. Tā tiek izmantota elementu atlasīšanai, pamatojoties uz nosacījumu.
Sintakse:
array.filter(callback(element[, index[, array]])[, thisArg])
callback
: Funkcija, kas jāizpilda katram elementam. Tai jāatgriežtrue
, lai paturētu elementu, vaifalse
, lai to atmestu.element
: Pašreizējais elements, kas tiek apstrādāts masīvā.index
(pēc izvēles): Pašreizējā elementa indekss.array
(pēc izvēles): Masīvs, uz kura tika izsauktsfilter
.thisArg
(pēc izvēles): Vērtība, kas jāizmanto kāthis
, izpildotcallback
.
Galvenās iezīmes:
- Atgriež jaunu masīvu.
- Oriģinālais masīvs paliek nemainīgs (nemainība).
- Jaunajā masīvā var būt mazāk elementu nekā oriģinālajā masīvā.
- Atzvanīšanas funkcijai jāatgriež Būla vērtība.
Piemērs: Pāru skaitļu filtrēšana
Filtrēsim skaitļu masīvu, lai paturētu tikai pāra skaitļus.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Izmantojot filter pāra skaitļu atlasei
const evenNumbers = numbers.filter(number => number % 2 === 0);
console.log(numbers); // Izvade: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(evenNumbers); // Izvade: [2, 4, 6, 8, 10]
Piemērs: Aktīvo lietotāju filtrēšana
No mūsu lietotāju masīva filtrēsim lietotājus, kuri ir atzīmēti kā aktīvi.
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);
/* Izvade:
[
{ id: 1, name: 'Alice', isActive: true },
{ id: 3, name: 'Charlie', isActive: true }
]
*/
3. Array.prototype.reduce()
Metode reduce()
izpilda lietotāja nodrošinātu “reducer” atzvanīšanas funkciju katram masīva elementam secīgi, nododot atgriezto vērtību no aprēķina iepriekšējam elementam. Reducera darbības beigu rezultāts visiem masīva elementiem ir viena vērtība.
Šī ir, iespējams, vispusīgākā no masīvu metodēm un ir daudzu funkcionālās programmēšanas modeļu stūrakmens, ļaujot “samazināt” masīvu līdz vienai vērtībai (piemēram, summai, reizinājumam, skaitam vai pat jaunam objektam vai masīvam).
Sintakse:
array.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
callback
: Funkcija, kas jāizpilda katram elementam.accumulator
: Vērtība, kas iegūta no iepriekšējā atzvanīšanas funkcijas izsaukuma. Pirmajā izsaukumā tā irinitialValue
, ja tā ir norādīta; pretējā gadījumā tas ir masīva pirmais elements.currentValue
: Pašreizējais elements, kas tiek apstrādāts.index
(pēc izvēles): Pašreizējā elementa indekss.array
(pēc izvēles): Masīvs, uz kura tika izsauktsreduce
.initialValue
(pēc izvēles): Vērtība, ko izmantot kā pirmo argumentu pirmajamcallback
izsaukumam. Ja nav norādītainitialValue
, masīva pirmais elements tiks izmantots kā sākotnējāaccumulator
vērtība, un iterācija sākas no otrā elementa.
Galvenās iezīmes:
- Atgriež vienu vērtību (kas var būt arī masīvs vai objekts).
- Oriģinālais masīvs paliek nemainīgs (nemainība).
initialValue
ir ļoti svarīga skaidrībai un kļūdu novēršanai, īpaši ar tukšiem masīviem vai, ja akumulatora tips atšķiras no masīva elementa tipa.
Piemērs: Skaitļu summēšana
Sasummēsim visus skaitļus mūsu masīvā.
const numbers = [1, 2, 3, 4, 5];
// Izmantojot reduce skaitļu summēšanai
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0); // 0 ir initialValue
console.log(sum); // Izvade: 15
Paskaidrojums:
- 1. izsaukums:
accumulator
ir 0,currentValue
ir 1. Atgriež 0 + 1 = 1. - 2. izsaukums:
accumulator
ir 1,currentValue
ir 2. Atgriež 1 + 2 = 3. - 3. izsaukums:
accumulator
ir 3,currentValue
ir 3. Atgriež 3 + 3 = 6. - Un tā tālāk, līdz tiek aprēķināta gala summa.
Piemērs: Objektu grupēšana pēc īpašības
Mēs varam izmantot reduce
, lai pārveidotu objektu masīvu par objektu, kurā vērtības ir grupētas pēc noteiktas īpašības. Grupēsim mūsu lietotājus pēc viņu `isActive` statusa.
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;
}, {}); // Tukšs objekts {} ir initialValue
console.log(groupedUsers);
/* Izvade:
{
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 }
]
}
*/
Piemērs: Gadījumu skaitīšana
Saskaitīsim katra augļa biežumu sarakstā.
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); // Izvade: { apple: 3, banana: 2, orange: 1 }
4. Array.prototype.forEach()
Lai gan forEach()
neatgriež jaunu masīvu un bieži tiek uzskatīta par imperatīvāku, jo tās galvenais mērķis ir izpildīt funkciju katram masīva elementam, tā joprojām ir fundamentāla metode, kas spēlē lomu funkcionālajās paradigmās, īpaši, ja nepieciešami blakusefekti vai ja tiek iterēts bez transformētas izvades nepieciešamības.
Sintakse:
array.forEach(callback(element[, index[, array]])[, thisArg])
Galvenās iezīmes:
- Atgriež
undefined
. - Izpilda norādītu funkciju vienu reizi katram masīva elementam.
- Bieži tiek izmantota blakusefektiem, piemēram, ierakstīšanai konsolē vai DOM elementu atjaunināšanai.
Piemērs: Katra elementa reģistrēšana
const messages = ['Hello', 'Functional', 'World'];
messages.forEach(message => console.log(message));
// Izvade:
// Hello
// Functional
// World
Piezīme: Transformācijām un filtrēšanai, map
un filter
ir vēlams to nemainības un deklaratīvās dabas dēļ. Izmantojiet forEach
, ja jums ir īpaši jāveic darbība katrai precei, neapkopojot rezultātus jaunā struktūrā.
5. Array.prototype.find()
un Array.prototype.findIndex()
Šīs metodes ir noderīgas, lai atrastu specifiskus elementus masīvā.
find()
: Atgriež vērtību pirmā elementa norādītajā masīvā, kas atbilst norādītajai pārbaudes funkcijai. Ja neviena vērtība neatbilst pārbaudes funkcijai, tiek atgrieztsundefined
.findIndex()
: Atgriež indeksu pirmā elementa norādītajā masīvā, kas atbilst norādītajai pārbaudes funkcijai. Pretējā gadījumā tiek atgriezts -1, norādot, ka neviens elements nav izturējis pārbaudi.
Piemērs: Lietotāja atrašana
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); // Izvade: { id: 2, name: 'Bob' }
console.log(bobIndex); // Izvade: 1
console.log(nonExistentUser); // Izvade: undefined
console.log(nonExistentIndex); // Izvade: -1
6. Array.prototype.some()
un Array.prototype.every()
Šīs metodes pārbauda, vai visi masīva elementi iztur pārbaudi, ko veic norādītā funkcija.
some()
: Pārbauda, vai vismaz viens elements masīvā iztur pārbaudi, ko veic norādītā funkcija. Tā atgriež Būla vērtību.every()
: Pārbauda, vai visi masīva elementi iztur pārbaudi, ko veic norādītā funkcija. Tā atgriež Būla vērtību.
Piemērs: Lietotāja statusa pārbaude
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); // Izvade: true (jo Bobs ir neaktīvs)
console.log(allAreActive); // Izvade: false (jo Bobs ir neaktīvs)
const allUsersActive = users.filter(user => user.isActive).length === users.length;
console.log(allUsersActive); // Izvade: false
// Alternatīva, tieši izmantojot every
const allUsersActiveDirect = users.every(user => user.isActive);
console.log(allUsersActiveDirect); // Izvade: false
Masīvu metožu ķēde sarežģītām darbībām
Funkcionālās programmēšanas patiesais spēks ar JavaScript masīviem parādās, ja jūs šīs metodes savienojat kopā. Tā kā lielākā daļa šo metožu atgriež jaunus masīvus (izņemot forEach
), jūs varat nemanāmi nodot vienas metodes izvadi citas ievadei, radot elegantus un salasāmus datu cauruļvadus.
Piemērs: Aktīvo lietotāju vārdu atrašana un viņu ID dubultošana
Atrodim visus aktīvos lietotājus, izgūstam viņu vārdus un pēc tam izveidojam jaunu masīvu, kurā katrs vārds ir priekšā ar numuru, kas atspoguļo tā indeksu *filtrētajā* sarakstā, un viņu ID ir dubultoti.
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) // Iegūst tikai aktīvos lietotājus
.map((user, index) => ({ // Pārveido katru aktīvo lietotāju
name: `${index + 1}. ${user.name}`,
doubledId: user.id * 2
}));
console.log(processedActiveUsers);
/* Izvade:
[
{ name: '1. Alice', doubledId: 2 },
{ name: '2. Charlie', doubledId: 6 },
{ name: '3. David', doubledId: 8 }
]
*/
Šī ķēdes pieeja ir deklaratīva: mēs norādām soļus (filtrēt, tad kartēt) bez skaidras cilpu pārvaldības. Tā ir arī nemainīga, jo katrs solis rada jaunu masīvu vai objektu, atstājot oriģinālo users
masīvu neskartu.
Nemainība praksē
Funkcionālā programmēšana lielā mērā balstās uz nemainību. Tas nozīmē, ka esošo datu struktūru modificēšanas vietā jūs izveidojat jaunas ar vēlamajām izmaiņām. JavaScript masīvu metodes, piemēram, map
, filter
un slice
, dabiski atbalsta to, atgriežot jaunus masīvus.
Kāpēc nemainība ir svarīga?
- Prognozējamība: Kodu kļūst vieglāk analizēt, jo jums nav jāizseko izmaiņām kopīgā mainīgā stāvoklī.
- Atkļūdošana: Ja rodas kļūdas, ir vieglāk noteikt problēmas avotu, ja dati netiek negaidīti modificēti.
- Veiktspēja: Noteiktos kontekstos (piemēram, ar stāvokļa pārvaldības bibliotēkām, piemēram, Redux vai React), nemainība nodrošina efektīvu izmaiņu noteikšanu.
- Paralēlisms: Nemainīgas datu struktūras pēc būtības ir drošas pavedienu ziņā, vienkāršojot paralēlo programmēšanu.
Ja jums ir jāveic darbība, kas tradicionāli mutētu masīvu (piemēram, elementa pievienošana vai noņemšana), jūs varat panākt nemainību, izmantojot tādas metodes kā slice
, izklājuma sintakse (...
) vai apvienojot citas funkcionālās metodes.
Piemērs: Elementa pievienošana nemainīgi
const originalArray = [1, 2, 3];
// Imperatīvais veids (modificē originalArray)
// originalArray.push(4);
// Funkcionālais veids, izmantojot izklājuma sintaksi
const newArrayWithPush = [...originalArray, 4];
console.log(originalArray); // Izvade: [1, 2, 3]
console.log(newArrayWithPush); // Izvade: [1, 2, 3, 4]
// Funkcionālais veids, izmantojot slice un savienošanu (tagad retāk sastopams)
const newArrayWithSlice = originalArray.slice(0, originalArray.length).concat(4);
console.log(newArrayWithSlice); // Izvade: [1, 2, 3, 4]
Piemērs: Elementa noņemšana nemainīgi
const originalArray = [1, 2, 3, 4, 5];
// Noņemt elementu ar indeksu 2 (vērtība 3)
// Funkcionālais veids, izmantojot slice un izklājuma sintaksi
const newArrayAfterSplice = [
...originalArray.slice(0, 2),
...originalArray.slice(3)
];
console.log(originalArray); // Izvade: [1, 2, 3, 4, 5]
console.log(newArrayAfterSplice); // Izvade: [1, 2, 4, 5]
// Izmantojot filter, lai noņemtu konkrētu vērtību
const newValueToRemove = 3;
const arrayWithoutValue = originalArray.filter(item => item !== newValueToRemove);
console.log(arrayWithoutValue); // Izvade: [1, 2, 4, 5]
Labākās prakses un progresīvas tehnikas
Kļūstot ērtāk ar funkcionālajām masīvu metodēm, apsveriet šādas prakses:
- Lasāmība vispirms: Lai gan ķēde ir spēcīga, pārmērīgi garas ķēdes var kļūt grūti lasāmas. Apsveriet sarežģītu operāciju sadalīšanu mazākās, nosauktās funkcijās vai starpposma mainīgo izmantošanu.
- Izprotiet `reduce` elastīgumu: Atcerieties, ka
reduce
var veidot masīvus vai objektus, nevis tikai vienas vērtības. Tas padara to neticami daudzpusīgu sarežģītām transformācijām. - Izvairieties no blakusefektiem atzvanīšanas funkcijās: Centieties saglabāt savas
map
,filter
unreduce
atzvanīšanas funkcijas tīras. Ja jums ir jāveic darbība ar blakusefektiem,forEach
bieži ir piemērotāka izvēle. - Izmantojiet bultu funkcijas: Bultu funkcijas (
=>
) nodrošina īsu sintaksi atzvanīšanas funkcijām un atšķirīgi apstrādā `this` saistīšanu, bieži padarot tās ideāli piemērotas funkcionālām masīvu metodēm. - Apsveriet bibliotēkas: Lai iegūtu progresīvākus funkcionālās programmēšanas modeļus vai ja jūs plaši strādājat ar nemainību, bibliotēkas, piemēram, Lodash/fp, Ramda vai Immutable.js, var būt noderīgas, lai gan tās nav stingri nepieciešamas, lai sāktu ar funkcionālām masīvu operācijām mūsdienu JavaScript.
Piemērs: Funkcionāla pieeja datu apvienošanai
Iedomājieties, ka jums ir pārdošanas dati no dažādiem reģioniem un vēlaties aprēķināt kopējo pārdošanas apjomu katram reģionam, tad atrast reģionu ar vislielāko pārdošanas apjomu.
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. Aprēķiniet kopējo pārdošanas apjomu katram reģionam, izmantojot reduce
const salesByRegion = salesData.reduce((acc, sale) => {
acc[sale.region] = (acc[sale.region] || 0) + sale.amount;
return acc;
}, {});
// salesByRegion būs: { North: 310, South: 330, East: 200 }
// 2. Pārveidojiet apkopoto objektu par objektu masīvu turpmākai apstrādei
const salesArray = Object.keys(salesByRegion).map(region => ({
region: region,
totalAmount: salesByRegion[region]
}));
// salesArray būs: [
// { region: 'North', totalAmount: 310 },
// { region: 'South', totalAmount: 330 },
// { region: 'East', totalAmount: 200 }
// ]
// 3. Atrodiet reģionu ar vislielāko pārdošanas apjomu, izmantojot reduce
const highestSalesRegion = salesArray.reduce((max, current) => {
return current.totalAmount > max.totalAmount ? current : max;
}, { region: '', totalAmount: -Infinity }); // Inicializēt ar ļoti mazu skaitli
console.log('Pārdošana pa reģioniem:', salesByRegion);
console.log('Pārdošanas masīvs:', salesArray);
console.log('Reģions ar lielāko pārdošanas apjomu:', highestSalesRegion);
/*
Izvade:
Pārdošana pa reģioniem: { North: 310, South: 330, East: 200 }
Pārdošanas masīvs: [
{ region: 'North', totalAmount: 310 },
{ region: 'South', totalAmount: 330 },
{ region: 'East', totalAmount: 200 }
]
Reģions ar lielāko pārdošanas apjomu: { region: 'South', totalAmount: 330 }
*/
Secinājums
Funkcionālā programmēšana ar JavaScript masīviem nav tikai stilistiska izvēle; tas ir spēcīgs veids, kā rakstīt tīrāku, prognozējamāku un robustāku kodu. Ieviešot tādas metodes kā map
, filter
un reduce
, jūs varat efektīvi transformēt, vaicāt un apkopot datus, vienlaikus ievērojot funkcionālās programmēšanas pamatprincipus, īpaši nemainību un tīras funkcijas.
Turpinot savu ceļojumu JavaScript izstrādē, šo funkcionālo modeļu integrēšana ikdienas darba plūsmā neapšaubāmi novedīs pie vieglāk uzturamām un mērogojamām lietojumprogrammām. Sāciet ar šo masīvu metožu eksperimentēšanu savos projektos, un drīz vien atklāsiet to milzīgo vērtību.