Prinsip pemrograman fungsional dalam JavaScript

Penulis materi, terjemahan yang kami terbitkan hari ini, mengatakan bahwa ia, setelah lama terlibat dalam pemrograman berorientasi objek, memikirkan kompleksitas sistem. Menurut John Ousterhout , kompleksitas adalah segalanya yang membuat pemahaman atau modifikasi perangkat lunak menjadi lebih sulit. Penulis artikel ini, setelah menyelesaikan beberapa penelitian, menemukan konsep pemrograman fungsional seperti kekebalan dan fungsi murni. Penggunaan konsep tersebut memungkinkan Anda untuk membuat fungsi yang tidak memiliki efek samping. Menggunakan fungsi-fungsi ini menyederhanakan dukungan sistem dan memberi programmer beberapa manfaat lain.

gambar

Di sini kita berbicara tentang pemrograman fungsional dan beberapa prinsip penting. Semua ini akan diilustrasikan oleh banyak contoh kode JavaScript.

Apa itu pemrograman fungsional?


Anda dapat membaca tentang apa pemrograman fungsional di Wikipedia . Yaitu, kita berbicara tentang fakta bahwa pemrograman fungsional adalah paradigma pemrograman di mana proses perhitungan diperlakukan sebagai penghitungan nilai-nilai fungsi dalam pemahaman matematika yang terakhir. Pemrograman fungsional melibatkan melakukan perhitungan hasil fungsi dari sumber data dan hasil fungsi lainnya, dan tidak menyiratkan penyimpanan eksplisit dari keadaan program. Dengan demikian, itu tidak menyiratkan variabilitas keadaan ini.

Sekarang, sebagai contoh, kita akan menganalisis beberapa ide pemrograman fungsional.

Fungsi murni


Fungsi murni adalah konsep dasar pertama yang perlu dipelajari untuk memahami esensi pemrograman fungsional.

Apa itu "fungsi murni"? Apa yang membuat fungsi β€œbersih”? Fungsi murni harus memenuhi persyaratan berikut:

  • Itu selalu mengembalikan, ketika melewati argumen yang sama untuk itu, hasil yang sama (fungsi-fungsi tersebut juga disebut deterministik).
  • Fungsi seperti itu tidak memiliki efek samping.

Pertimbangkan properti pertama dari fungsi murni, yaitu kenyataan bahwa mereka, ketika menyampaikan argumen yang sama kepada mereka, selalu mengembalikan hasil yang sama.

▍ Berfungsi argumen dan mengembalikan nilai


Bayangkan kita perlu membuat fungsi yang menghitung luas lingkaran. Fungsi yang tidak bersih akan mengambil, sebagai parameter, jari-jari lingkaran ( radius ), setelah itu akan mengembalikan nilai perhitungan radius * radius * PI ekspresi radius * radius * PI :

 const PI = 3.14; function calculateArea(radius) { return radius * radius * PI; } calculateArea(10); //  314 

Mengapa fungsi ini tidak bisa disebut murni? Faktanya adalah bahwa ia menggunakan konstanta global, yang tidak diteruskan sebagai argumen.

Sekarang bayangkan bahwa beberapa ahli matematika sampai pada kesimpulan bahwa nilai PI konstan harus menjadi angka 42 , karena itu nilai konstanta ini diubah.

Sekarang fungsi yang tidak murni, ketika dilewatkan nilai input yang sama, angka 10 , akan mengembalikan nilai 10 * 10 * 42 = 4200 . Ternyata menggunakan di sini sama seperti pada contoh sebelumnya, nilai parameter radius , fungsi mengembalikan hasil yang berbeda. Mari kita perbaiki ini:

 const PI = 3.14; function calculateArea(radius, pi) { return radius * radius * pi; } calculateArea(10, PI); //  314 

Sekarang, saat memanggil fungsi ini, kita akan selalu memberikan argumen pi . Akibatnya, fungsi hanya akan bekerja dengan apa yang diteruskan ke sana ketika dipanggil, tanpa menggunakan entitas global. Jika kita menganalisis perilaku fungsi ini, kita dapat sampai pada kesimpulan berikut:

  • Jika fungsi melewati argumen radius 10 dan pi 3.14 , itu akan selalu mengembalikan hasil yang sama - 314 .
  • Ketika dipanggil dengan argumen radius 10 dan pi 42 , ia akan selalu mengembalikan 4200 .

Membaca file


Jika fungsi kita membaca file, maka itu tidak akan bersih. Faktanya adalah bahwa isi file dapat berubah.

 function charactersCounter(text) { return `Character count: ${text.length}`; } function analyzeFile(filename) { let fileContent = open(filename); return charactersCounter(fileContent); } 

Pembuatan angka acak


Fungsi apa pun yang mengandalkan generator angka acak tidak boleh murni.

 function yearEndEvaluation() { if (Math.random() > 0.5) {   return "You get a raise!"; } else {   return "Better luck next year!"; } } 

Sekarang mari kita bicara tentang efek samping.

▍ Efek samping


Contoh efek samping yang dapat terjadi ketika suatu fungsi dipanggil adalah modifikasi variabel global atau argumen yang diteruskan ke fungsi dengan referensi.

Misalkan kita perlu membuat fungsi yang mengambil bilangan bulat dan menambah angka itu dengan 1. Inilah tampilan dari penerapan ide serupa:

 let counter = 1; function increaseCounter(value) { counter = value + 1; } increaseCounter(counter); console.log(counter); // 2 

Ada counter variabel global. Fungsi kami, yang tidak murni, menerima nilai ini sebagai argumen dan menimpanya, menambahkannya ke nilai sebelumnya.

Variabel global berubah, serupa dalam pemrograman fungsional tidak diterima.

Dalam kasus kami, nilai variabel global dimodifikasi. Bagaimana cara membuat fungsi increaseCounter() bersih dalam kondisi ini? Sebenarnya, ini sangat sederhana:

 let counter = 1; function increaseCounter(value) { return value + 1; } increaseCounter(counter); // 2 console.log(counter); // 1 

Seperti yang Anda lihat, fungsi mengembalikan 2 , tetapi nilai counter variabel global tidak berubah. Di sini kita dapat menyimpulkan bahwa fungsi mengembalikan nilai yang diteruskan ke sana, meningkat sebesar 1 , sementara tidak mengubah apa pun.

Jika Anda mengikuti dua aturan di atas untuk menulis fungsi murni, ini akan membuatnya lebih mudah untuk dinavigasi dalam program yang dibuat menggunakan fungsi tersebut. Ternyata setiap fungsi akan diisolasi dan tidak akan mempengaruhi bagian-bagian program di luarnya.

Fungsi murni stabil, konsisten, dan dapat diprediksi. Menerima data input yang sama, fungsi seperti itu selalu mengembalikan hasil yang sama. Ini menyelamatkan programmer dari mencoba memperhitungkan kemungkinan situasi di mana transfer fungsi dari parameter yang sama mengarah ke hasil yang berbeda, karena ini tidak mungkin dengan fungsi murni.

▍ Kekuatan fungsi murni


Di antara kekuatan fungsi murni adalah fakta bahwa kode yang ditulis dengan menggunakannya lebih mudah untuk diuji. Secara khusus, Anda tidak perlu membuat objek rintisan. Ini memungkinkan pengujian unit fungsi murni dalam berbagai konteks:

  • Jika parameter A diteruskan ke fungsi, nilai pengembalian B diharapkan.
  • Jika parameter C diteruskan ke fungsi, nilai pengembalian D diharapkan.

Sebagai contoh sederhana dari ide ini, kita dapat memberikan fungsi yang mengambil array angka, dan diharapkan akan bertambah satu setiap nomor array ini, mengembalikan array baru dengan hasil:

 let list = [1, 2, 3, 4, 5]; function incrementNumbers(list) { return list.map(number => number + 1); } 

Di sini kita meneruskan array angka ke fungsi, setelah itu kita menggunakan metode array map() , yang memungkinkan kita untuk memodifikasi setiap elemen array dan membentuk array baru yang dikembalikan oleh fungsi. Kami memanggil fungsi dengan mengirimkannya array list :

 incrementNumbers(list); //  [2, 3, 4, 5, 6] 

Dari fungsi ini diharapkan bahwa, setelah menerima larik bentuk [1, 2, 3, 4, 5] , ia akan mengembalikan larik baru [2, 3, 4, 5, 6] . Begitulah cara kerjanya.

Kekebalan


Kekebalan suatu entitas tertentu dapat digambarkan sebagai fakta bahwa ia tidak berubah seiring waktu, atau sebagai ketidakmungkinan mengubah entitas ini.

Jika mereka mencoba mengubah objek yang tidak dapat diubah, ini tidak akan berhasil. Sebagai gantinya, Anda harus membuat objek baru yang berisi nilai baru.

Misalnya, JavaScript sering menggunakan for loop. Dalam perjalanan karyanya, seperti yang ditunjukkan di bawah ini, variabel bisa berubah digunakan:

 var values = [1, 2, 3, 4, 5]; var sumOfValues = 0; for (var i = 0; i < values.length; i++) { sumOfValues += values[i]; } sumOfValues // 15 

Pada setiap iterasi dari loop, nilai variabel i dan nilai variabel global (dapat dianggap sebagai keadaan program) sumOfValues . Bagaimana dalam situasi seperti itu untuk mempertahankan keabadian entitas? Jawabannya terletak pada penggunaan rekursi.

 let list = [1, 2, 3, 4, 5]; let accumulator = 0; function sum(list, accumulator) { if (list.length == 0) {   return accumulator; } return sum(list.slice(1), accumulator + list[0]); } sum(list, accumulator); // 15 list; // [1, 2, 3, 4, 5] accumulator; // 0 

Ada sum() fungsi sum() , yang mengambil array angka. Fungsi ini memanggil dirinya sendiri hingga array kosong (ini adalah kasus dasar dari algoritma rekursif kami). Pada setiap "iterasi" tersebut, kami menambahkan nilai salah satu elemen array ke parameter fungsi accumulator , tanpa mempengaruhi accumulator variabel global. Dalam hal ini, list variabel global dan accumulator tetap tidak berubah, nilai-nilai yang sama disimpan di dalamnya sebelum dan sesudah pemanggilan fungsi.

Perlu dicatat bahwa untuk mengimplementasikan algoritma seperti itu, Anda dapat menggunakan metode reduce array. Kami akan membicarakan ini di bawah ini.

Dalam pemrograman, tugas tersebar luas saat diperlukan, berdasarkan pada templat tertentu dari suatu objek, untuk membuat representasi finalnya. Bayangkan bahwa kita memiliki string yang perlu dikonversi ke tampilan yang sesuai untuk digunakan sebagai bagian dari URL yang mengarah ke sumber daya tertentu.

Jika kita menyelesaikan masalah ini menggunakan Ruby dan menggunakan prinsip-prinsip OOP, pertama-tama kita akan membuat sebuah kelas, katakanlah, menyebutnya UrlSlugify , dan kemudian buat metode untuk slugify! kelas ini slugify! yang digunakan untuk mengkonversi string.

 class UrlSlugify attr_reader :text def initialize(text)   @text = text end def slugify!   text.downcase!   text.strip!   text.gsub!(' ', '-') end end UrlSlugify.new(' I will be a url slug   ').slugify! # "i-will-be-a-url-slug" 

Kami telah mengimplementasikan algoritme, dan ini luar biasa. Di sini kita melihat pendekatan penting untuk pemrograman, ketika kita, memproses garis, melukis setiap langkah transformasi. Yaitu, pertama-tama kita mengurangi karakternya menjadi huruf kecil, kemudian menghapus spasi yang tidak perlu, dan akhirnya mengubah spasi yang tersisa di dasbor.

Namun, selama transformasi ini, terjadi mutasi status program.

Anda dapat mengatasi masalah mutasi dengan membuat fungsi atau memanggil fungsi panggilan. Dengan kata lain, hasil yang dikembalikan oleh fungsi akan digunakan sebagai input untuk fungsi berikutnya, dan juga untuk semua fungsi dalam rantai. Dalam hal ini, string asli tidak akan berubah.

 let string = " I will be a url slug   "; function slugify(string) { return string.toLowerCase()   .trim()   .split(" ")   .join("-"); } slugify(string); // i-will-be-a-url-slug 

Di sini kami menggunakan fungsi-fungsi berikut, yang diwakili dalam JavaScript dengan metode string dan array standar:

  • toLowerCase : Mengubah karakter string menjadi toLowerCase .
  • trim : menghapus spasi putih dari awal dan akhir baris.
  • split : membagi string menjadi beberapa bagian, menempatkan kata-kata yang dipisahkan oleh spasi dalam sebuah array.
  • join : membentuk string dengan kata-kata yang dipisahkan oleh tanda hubung berdasarkan array dengan kata-kata.

Keempat fungsi ini memungkinkan Anda untuk membuat fungsi untuk mengonversi string yang tidak mengubah string ini sendiri.

Tautan transparansi


Buat kotak fungsi square() yang mengembalikan hasil mengalikan angka dengan angka yang sama:

 function square(n) { return n * n; } 

Ini adalah fungsi murni yang akan selalu, untuk nilai input yang sama, mengembalikan nilai output yang sama.

 square(2); // 4 square(2); // 4 square(2); // 4 // ... 

Misalnya, tidak peduli berapa banyak angka 2 yang diteruskan, fungsi ini akan selalu mengembalikan angka 4 . Hasilnya, ternyata pemanggilan bentuk square(2) dapat diganti dengan angka 4 . Ini berarti bahwa fungsi kami memiliki sifat transparansi referensial.

Secara umum, kita dapat mengatakan bahwa jika suatu fungsi selalu mengembalikan hasil yang sama untuk nilai input yang sama yang diteruskan, ia memiliki transparansi referensial.

▍Fungsi murni + data tidak berubah = transparansi referensial


Dengan menggunakan ide yang dikedepankan dalam judul bagian ini, Anda dapat memo fungsi. Misalkan kita memiliki fungsi seperti ini:

 function sum(a, b) { return a + b; } 

Kami menyebutnya seperti ini:

 sum(3, sum(5, 8)); 

sum(5, 8) panggilan sum(5, 8) selalu memberi 13 . Oleh karena itu, panggilan di atas dapat ditulis ulang sebagai berikut:

 sum(3, 13); 

Ungkapan ini, pada gilirannya, selalu memberi 16 . Sebagai hasilnya, itu dapat digantikan oleh konstanta numerik dan memoized .

Berfungsi sebagai Objek Kelas Pertama


Gagasan mempersepsikan fungsi sebagai objek dari kelas pertama adalah bahwa fungsi tersebut dapat dianggap sebagai nilai dan bekerja dengannya sebagai data. Fitur fungsi berikut dapat dibedakan:

  • Referensi ke fungsi dapat disimpan dalam konstanta dan variabel dan melaluinya akses ke fungsi.
  • Fungsi dapat diteruskan ke fungsi lain sebagai parameter.
  • Fungsi dapat dikembalikan dari fungsi lain.

Yaitu, ini tentang mempertimbangkan fungsi sebagai nilai dan memperlakukannya seperti data. Dengan pendekatan ini, Anda dapat menggabungkan berbagai fungsi dalam proses pembuatan fungsi baru yang mengimplementasikan fitur baru.

Bayangkan bahwa kita memiliki fungsi yang menambahkan dua nilai numerik yang diteruskan ke sana, lalu mengalikannya dengan 2 dan mengembalikan apa yang ternyata:

 function doubleSum(a, b) { return (a + b) * 2; } 

Sekarang kita menulis fungsi yang mengurangi yang kedua dari nilai numerik pertama yang diteruskan, mengalikan apa yang terjadi dengan 2 , dan mengembalikan nilai yang dihitung:

 function doubleSubtraction(a, b) { return (a - b) * 2; } 

Fungsi-fungsi ini memiliki logika yang sama, mereka hanya berbeda dalam operasi apa yang mereka lakukan dengan angka-angka yang diberikan kepada mereka. Jika kita dapat menganggap fungsi sebagai nilai dan meneruskannya sebagai argumen ke fungsi lain, ini berarti bahwa kita dapat membuat fungsi yang menerima dan menggunakan fungsi lain yang menjelaskan fitur perhitungan. Pertimbangan ini memungkinkan kami untuk mencapai konstruksi berikut:

 function sum(a, b) { return a + b; } function subtraction(a, b) { return a - b; } function doubleOperator(f, a, b) { return f(a, b) * 2; } doubleOperator(sum, 3, 1); // 8 doubleOperator(subtraction, 3, 1); // 4 

Seperti yang Anda lihat, sekarang fungsi doubleOperator() memiliki parameter f , dan fungsi yang diwakilinya digunakan untuk memproses parameter a dan b . Fungsi sum() dan substraction() dilewatkan ke fungsi doubleOperator() , pada kenyataannya, memungkinkan Anda untuk mengontrol perilaku fungsi doubleOperator() , mengubahnya sesuai dengan logika yang diterapkan di dalamnya.

Fungsi Orde Tinggi


Berbicara tentang fungsi tingkat tinggi, yang kami maksud adalah fungsi yang ditandai oleh setidaknya satu dari fitur berikut:

  • Suatu fungsi mengambil fungsi lain sebagai argumen (mungkin ada beberapa fungsi seperti itu).
  • Fungsi mengembalikan fungsi lain sebagai hasil kerjanya.

Anda mungkin sudah terbiasa dengan filter() metode array JS standar filter() , map() dan reduce() . Mari kita bicarakan mereka.

▍ Filter array dan metode filter ()


Misalkan kita memiliki kumpulan elemen tertentu yang ingin kita filter dengan beberapa atribut elemen koleksi ini dan membentuk koleksi baru. Fungsi filter() mengharapkan untuk menerima beberapa kriteria untuk mengevaluasi elemen, atas dasar itu menentukan apakah akan memasukkan elemen atau tidak dalam koleksi yang dihasilkan. Kriteria ini ditentukan oleh fungsi yang diteruskan ke sana, yang mengembalikan true jika fungsi filter() harus menyertakan elemen dalam koleksi akhir, jika tidak maka mengembalikan false .

Bayangkan bahwa kita memiliki array bilangan bulat dan kami ingin memfilternya dengan mendapatkan array baru yang hanya berisi angka genap dari array asli.

Pendekatan imperatif


Saat menerapkan pendekatan imperatif untuk menyelesaikan masalah ini menggunakan JavaScript, kita perlu menerapkan urutan tindakan berikut:

  • Buat array kosong untuk elemen baru (sebut saja evenNumbers ).
  • Iterate di atas array asli bilangan bulat (sebut saja numbers ).
  • Masukkan bilangan genap yang ditemukan di dalam array numbers evenNumbers array evenNumbers .

Begini tampilannya implementasi algoritma ini:

 var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; var evenNumbers = []; for (var i = 0; i < numbers.length; i++) { if (numbers[i] % 2 == 0) {   evenNumbers.push(numbers[i]); } } console.log(evenNumbers); // (6) [0, 2, 4, 6, 8, 10] 

Selain itu, kita dapat menulis sebuah fungsi (sebut saja even() ), yang, jika angkanya genap, mengembalikan true , dan jika itu ganjil, mengembalikan false , lalu meneruskannya ke metode array filter() , yang, dengan mengeceknya, masing-masing elemen array , akan membentuk array baru yang hanya berisi angka genap:

 function even(number) { return number % 2 == 0; } let listOfNumbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; listOfNumbers.filter(even); // [0, 2, 4, 6, 8, 10] 

Di sini, omong-omong, adalah solusi untuk satu masalah menarik tentang filter array , yang saya selesaikan saat mengerjakan tugas pemrograman fungsional pada Hacker Rank . Dengan kondisi masalah, perlu untuk menyaring array bilangan bulat, hanya menampilkan elemen-elemen yang kurang dari nilai x diberikan.

Solusi penting untuk masalah ini dalam JavaScript mungkin terlihat seperti ini:

 var filterArray = function(x, coll) { var resultArray = []; for (var i = 0; i < coll.length; i++) {   if (coll[i] < x) {     resultArray.push(coll[i]);   } } return resultArray; } console.log(filterArray(3, [10, 9, 8, 2, 7, 5, 1, 3, 0])); // (3) [2, 1, 0] 

Inti dari pendekatan imperatif adalah bahwa kami menguraikan urutan tindakan yang dilakukan oleh fungsi. Yaitu, kami menggambarkan pencarian array, membandingkan elemen array saat ini dengan x dan menempatkan elemen ini dalam array resultArray jika lolos dari tes.

Pendekatan deklaratif


Bagaimana cara beralih ke pendekatan deklaratif untuk menyelesaikan masalah ini dan penggunaan metode filter() sesuai, yang merupakan fungsi tingkat tinggi? Misalnya, mungkin terlihat seperti ini:

 function smaller(number) { return number < this; } function filterArray(x, listOfNumbers) { return listOfNumbers.filter(smaller, x); } let numbers = [10, 9, 8, 2, 7, 5, 1, 3, 0]; filterArray(3, numbers); // [2, 1, 0] 

Anda mungkin merasa tidak biasa menggunakan this dalam fungsi yang smaller() dalam contoh ini, tetapi tidak ada yang rumit di sini. Kata this adalah argumen kedua ke metode filter() . Dalam contoh kita, ini adalah angka 3 diwakili oleh parameter x dari filterArray() . Angka ini ditunjukkan oleh this .

Pendekatan yang sama dapat digunakan jika array berisi entitas yang memiliki struktur yang cukup kompleks, misalnya objek. Misalkan kita memiliki array yang menyimpan objek yang berisi nama-nama orang yang diwakili oleh properti name , dan informasi tentang usia orang-orang ini diwakili oleh properti age . Beginilah bentuk array:

 let people = [ { name: "TK", age: 26 }, { name: "Kaio", age: 10 }, { name: "Kazumi", age: 30 } ]; 

Kami ingin memfilter array ini dengan memilih hanya objek yang orang-orang yang usianya melebihi 21 tahun. Inilah cara mengatasi masalah ini:

 function olderThan21(person) { return person.age > 21; } function overAge(people) { return people.filter(olderThan21); } overAge(people); // [{ name: 'TK', age: 26 }, { name: 'Kazumi', age: 30 }] 

Di sini kita memiliki array dengan objek yang mewakili orang. Kami memeriksa elemen-elemen dari array ini menggunakan fungsi olderThan21() . Dalam hal ini, saat memeriksa, kami merujuk ke properti age setiap elemen, memeriksa apakah nilai properti ini melebihi 21 . Kami meneruskan fungsi ini ke metode filter() , yang memfilter array.

▍ Memproses elemen array dan metode map ()


Metode map() digunakan untuk mengonversi elemen array. Dia menerapkan fungsi yang diteruskan ke setiap elemen array, dan kemudian membangun array baru yang terdiri dari elemen yang diubah.

Mari kita lanjutkan percobaan dengan array people yang sudah Anda kenal. Sekarang kita tidak akan memfilter array ini berdasarkan pada properti objek age . Kita perlu membuat berdasarkan daftar garis dari bentuk TK is 26 years old . Dalam pendekatan ini, garis-garis di mana elemen berubah menjadi akan dibangun sesuai dengan template p.name is p.age years old , di mana p.name dan p.age adalah nilai-nilai properti yang sesuai dari elemen-elemen dari array people .

Pendekatan imperatif untuk menyelesaikan masalah ini dalam JavaScript terlihat seperti ini:

 var people = [ { name: "TK", age: 26 }, { name: "Kaio", age: 10 }, { name: "Kazumi", age: 30 } ]; var peopleSentences = []; for (var i = 0; i < people.length; i++) { var sentence = people[i].name + " is " + people[i].age + " years old"; peopleSentences.push(sentence); } console.log(peopleSentences); // ['TK is 26 years old', 'Kaio is 10 years old', 'Kazumi is 30 years old'] 

Jika Anda menggunakan pendekatan deklaratif, Anda mendapatkan yang berikut:

 function makeSentence(person) { return `${person.name} is ${person.age} years old`; } function peopleSentences(people) { return people.map(makeSentence); } peopleSentences(people); // ['TK is 26 years old', 'Kaio is 10 years old', 'Kazumi is 30 years old'] 

Faktanya, ide utama di sini adalah bahwa Anda perlu melakukan sesuatu dengan setiap elemen dari array asli, dan kemudian menempatkannya dalam array baru.

Ini adalah tugas lain dengan Hacker Rank, yang didedikasikan untuk memperbarui daftar . Yaitu, kita berbicara tentang mengubah nilai elemen array numerik yang ada ke nilai absolutnya. Jadi, misalnya, ketika memproses array [1, 2, 3, -4, 5] ia akan mengambil bentuk [1, 2, 3, 4, 5] karena nilai absolut -4 adalah 4 .

Berikut adalah contoh dari solusi sederhana untuk masalah ini, ketika kita beralih pada array dan mengubah nilai elemen-elemennya ke nilai absolutnya.

 var values = [1, 2, 3, -4, 5]; for (var i = 0; i < values.length; i++) { values[i] = Math.abs(values[i]); } console.log(values); // [1, 2, 3, 4, 5] 

Di sini, untuk mengonversi nilai-nilai elemen array, metode Math.abs() digunakan, elemen yang diubah ditulis ke tempat yang sama di mana mereka berada sebelum konversi.

.

, , , . . , , , .

, , map() . ?

, abs() , , .

 Math.abs(-1); // 1 Math.abs(1); // 1 Math.abs(-2); // 2 Math.abs(2); // 2 

, , .

, , Math.abs() map() . , ? map() . :

 let values = [1, 2, 3, -4, 5]; function updateListMap(values) { return values.map(Math.abs); } updateListMap(values); // [1, 2, 3, 4, 5] 

, , , , , .

▍ reduce()


reduce() .

. , -. Product 1 , Product 2 , Product 3 Product 4 . .

, . Misalnya, mungkin terlihat seperti ini:

 var orders = [ { productTitle: "Product 1", amount: 10 }, { productTitle: "Product 2", amount: 30 }, { productTitle: "Product 3", amount: 20 }, { productTitle: "Product 4", amount: 60 } ]; var totalAmount = 0; for (var i = 0; i < orders.length; i++) { totalAmount += orders[i].amount; } console.log(totalAmount); // 120 

reduce() , ( sumAmount() ), , reduce() :

 let shoppingCart = [ { productTitle: "Product 1", amount: 10 }, { productTitle: "Product 2", amount: 30 }, { productTitle: "Product 3", amount: 20 }, { productTitle: "Product 4", amount: 60 } ]; const sumAmount = (currentTotalAmount, order) => currentTotalAmount + order.amount; function getTotalAmount(shoppingCart) { return shoppingCart.reduce(sumAmount, 0); } getTotalAmount(shoppingCart); // 120 

shoppingCart , , sumAmount() , ( order , amount ), β€” currentTotalAmount .

reduce() , getTotalAmount() , sumAmount() , 0 .

map() reduce() . «»? , map() shoppingCart , amount , reduce() sumAmount() . :

 const getAmount = (order) => order.amount; const sumAmount = (acc, amount) => acc + amount; function getTotalAmount(shoppingCart) { return shoppingCart   .map(getAmount)   .reduce(sumAmount, 0); } getTotalAmount(shoppingCart); // 120 

getAmount() amount . map() , , , [10, 30, 20, 60] . , reduce() , .

▍ filter(), map() reduce()


, , filter() , map() reduce() . , , .

-. , :

 let shoppingCart = [ { productTitle: "Functional Programming", type: "books", amount: 10 }, { productTitle: "Kindle", type: "eletronics", amount: 30 }, { productTitle: "Shoes", type: "fashion", amount: 20 }, { productTitle: "Clean Code", type: "books", amount: 60 } ] 

. :

  • type , , books .
  • , .
  • .

, :

 let shoppingCart = [ { productTitle: "Functional Programming", type: "books", amount: 10 }, { productTitle: "Kindle", type: "eletronics", amount: 30 }, { productTitle: "Shoes", type: "fashion", amount: 20 }, { productTitle: "Clean Code", type: "books", amount: 60 } ] const byBooks = (order) => order.type == "books"; const getAmount = (order) => order.amount; const sumAmount = (acc, amount) => acc + amount; function getTotalAmount(shoppingCart) { return shoppingCart   .filter(byBooks)   .map(getAmount)   .reduce(sumAmount, 0); } getTotalAmount(shoppingCart); // 70 

Ringkasan


JavaScript-. , .

Pembaca yang budiman! ?



Source: https://habr.com/ru/post/id434112/


All Articles