Apakah Fungsi Murni dalam JavaScript?

Fungsi murni adalah blok bangunan atom dalam pengaturcaraan berfungsi. Mereka dipuji kerana kesederhanaan dan kebolehujian mereka.

Catatan ini merangkumi senarai semak ringkas untuk mengetahui sama ada fungsi itu tulen atau tidak.

Senarai Semak

Fungsi mesti lulus dua ujian untuk dianggap "suci":

  1. Input yang sama selalu menghasilkan output yang sama
  2. Tiada kesan sampingan

Mari kita zum setiap satu.

1. Input Sama => Output Sama

Bandingkan ini:

const add = (x, y) => x + y; add(2, 4); // 6 

Untuk ini:

let x = 2; const add = (y) => { x += y; }; add(4); // x === 6 (the first time) 

Fungsi Murni = Hasil yang Konsisten

Contoh pertama mengembalikan nilai berdasarkan parameter yang diberikan, tidak kira di mana / kapan anda memanggilnya.

Sekiranya anda lulus 2dan 4, anda akan sentiasa mendapat 6.

Tidak ada yang lain yang mempengaruhi output.

Fungsi Tidak Murni = Hasil Tidak Konsisten

Contoh kedua tidak mengembalikan apa-apa. Ia bergantung pada keadaan bersama untuk melakukan tugasnya dengan menambahkan pemboleh ubah di luar skopnya sendiri.

Corak ini adalah bahan bakar mimpi buruk pemaju.

Keadaan bersama memperkenalkan pergantungan masa. Anda mendapat hasil yang berbeza bergantung pada masa anda memanggil fungsi tersebut. Hasil pertama kali masuk 6, lain kali adalah 10dan seterusnya.

Versi Mana Yang Lebih Mudah Ditentukan?

Siapa yang kurang cenderung membiak pepijat yang hanya berlaku dalam keadaan tertentu?

Siapa yang lebih cenderung berjaya dalam persekitaran multi-thread di mana pergantungan masa dapat memecahkan sistem?

Pasti yang pertama.

2. Tiada Kesan Sampingan

Ujian ini sendiri adalah senarai semak. Beberapa contoh kesan sampingan adalah

  1. Merapatkan input anda
  2. console.log
  3. Panggilan HTTP (AJAX / pengambilan)
  4. Menukar sistem fail (fs)
  5. Menanyakan DOM

Pada dasarnya apa-apa kerja yang dilakukan fungsi yang tidak berkaitan dengan pengiraan output akhir.

Berikut adalah fungsi tidak bersih dengan kesan sampingan.

Tidak Begitu Buruk

const impureDouble = (x) => { console.log('doubling', x); return x * 2; }; const result = impureDouble(4); console.log({ result }); 

console.logadalah kesan sampingan di sini tetapi, dalam praktiknya, ia tidak akan membahayakan kita. Kami masih akan mendapat output yang sama, dengan input yang sama.

Ini , bagaimanapun, boleh menyebabkan masalah.

"Tidak Cukup" Mengubah Objek

const impureAssoc = (key, value, object) => { object[key] = value; }; const person = { name: 'Bobo' }; const result = impureAssoc('shoeSize', 400, person); console.log({ person, result }); 

Pemboleh ubah, persontelah diubah selamanya kerana fungsi kami memperkenalkan penyataan tugasan.

Keadaan bersama bermaksud impureAssockesannya tidak lagi jelas. Memahami kesannya pada sistem sekarang melibatkan mengesan setiap pemboleh ubah yang pernah disentuh dan mengetahui sejarahnya.

Keadaan bersama = pergantungan masa.

Kita dapat membersihkan impureAssocdengan hanya mengembalikan objek baru dengan sifat yang kita inginkan.

Menyucikannya

const pureAssoc = (key, value, object) => ({ ...object, [key]: value }); const person = { name: 'Bobo' }; const result = pureAssoc('shoeSize', 400, person); console.log({ person, result }); 

Sekarang pureAssocmengembalikan hasil yang boleh diuji dan kami tidak akan bimbang jika ia secara senyap mengubah sesuatu di tempat lain.

Anda juga boleh melakukan perkara berikut dan tetap murni:

Cara Murni yang Lain

const pureAssoc = (key, value, object) => { const newObject = { ...object }; newObject[key] = value; return newObject; }; const person = { name: 'Bobo' }; const result = pureAssoc('shoeSize', 400, person); console.log({ person, result }); 

Mematikan input anda boleh membahayakan, tetapi memautkan salinannya tidak menjadi masalah. Hasil akhir kami masih berfungsi, boleh diramalkan berfungsi yang berfungsi di mana sahaja / bila anda memanggilnya.

Mutasi terhad pada ruang lingkup kecil itu dan anda masih mengembalikan nilai.

Objek Pengklonan Dalam

Awas! Menggunakan operator penyebaran ...membuat salinan objek yang cetek . Salinan cetek tidak selamat dari mutasi bersarang.

Terima kasih Rodrigo Fernández Díaz kerana mengingatkan saya!

Mutasi Bersarang Tidak Selamat

const person = { name: 'Bobo', address: { street: 'Main Street', number: 123 } }; const shallowPersonClone = { ...person }; shallowPersonClone.address.number = 456; console.log({ person, shallowPersonClone }); 

Keduanya persondan shallowPersonClonebermutasi kerana anak mereka berkongsi rujukan yang sama!

Mutasi Bersarang Selamat

To safely mutate nested properties, we need a deep clone.

const person = { name: 'Bobo', address: { street: 'Main Street', number: 123 } }; const deepPersonClone = JSON.parse(JSON.stringify(person)); deepPersonClone.address.number = 456; console.log({ person, deepPersonClone }); 

Now you’re guaranteed safety because they’re truly two separate entities!

Summary

  • A function’s pure if it’s free from side-effects and returns the same output, given the same input.
  • Side-effects include: mutating input, HTTP calls, writing to disk, printing to the screen.
  • You can safely clone, thenmutate, your input. Just leave the original one untouched.
  • Spread syntax ( syntax) is the easiest way to shallowly clone objects.
  • JSON.parse(JSON.stringify(object)) is the easiest way to deeply clone objects. Thanks again Rodrigo Fernández Díaz!

My Free Course

This tutorial was from my completely free course on Educative.io, Functional Programming Patterns With RamdaJS!

Please consider taking/sharing it if you enjoyed this content.

It’s full of lessons, graphics, exercises, and runnable code samples to teach you a basic functional programming style using RamdaJS.

Thanks for reading! Until next time.