Apa manfaat dari suatu fungsi tanpa parameter yang hanya memanggil fungsi lain

21

Tutorial (untuk Javascript) yang saya lakukan menyarankan agar kita menulis fungsi seperti ini:

function sayHello() {
   //Some comments explaining the next line
   window.alert("Hello");
}

Selain kebingungan, adakah manfaat menulis sesuatu seperti ini di kehidupan nyata? Jika demikian, apa manfaatnya?

Daniel
sumber
14
Mungkin hanya mencoba menunjukkan kepada Anda bagaimana mendefinisikan fungsi Anda sendiri.
Doval
4
Saya tidak akan pernah menulis kode sedemikian rupa untuk mengaburkannya - kode untuk programmer mudah dibaca, bukan sebaliknya. Gunakan obfuscater untuk kebingungan.
rhughes
32
Manfaatnya adalah membungkus fungsi dengan parameter. Dengan cara ini jika nanti Anda ingin membuat aplikasi Spanyol, Anda hanya perlu mengubah "Halo" menjadi "Ola" di satu tempat.
Pieter B
9
@PieterB sebenarnya, "Hola"
rev
29
@PieterB - Dan jika Anda menemukan Anda salah mengeja "Hola" Anda hanya perlu memperbaikinya di satu tempat.
Daniel R Hicks

Jawaban:

60

Maafkan ingatan saya jika saya memiliki kesalahan ini ... Javascript bukan bahasa implementasi pilihan saya.

Ada beberapa alasan mengapa seseorang ingin memiliki fungsi tanpa arg membungkus panggilan fungsi lain. Sementara panggilan sederhana window.alert("Hello");adalah sesuatu yang bisa Anda bayangkan alih-alih menelepon langsung, bukan sayHello().

Tetapi bagaimana jika ada lebih dari itu? Anda punya selusin tempat di mana Anda ingin menelepon sayHello()dan window.alert("Hello");malah menulis . Sekarang Anda ingin melakukan a window.alert("Hello, it is now " + new Date()). Jika Anda membungkus semua panggilan itu saat sayHello()Anda mengubahnya di satu tempat. Jika tidak, Anda mengubahnya di selusin tempat. Ini menyentuh pada Don't Repeat Yourself . Anda melakukannya karena Anda tidak ingin harus melakukannya selusin kali di masa depan.

Saya bekerja dengan perpustakaan i18n / l10n di masa lalu yang menggunakan fungsi untuk melakukan lokalisasi sisi klien dari teks. Pertimbangkan sayHello()fungsinya. Anda bisa mencetaknya holasaat pengguna dilokalkan ke bahasa Spanyol. Ini bisa terlihat seperti:

function sayHello() {
  var language = window.navigator.userLanguage || window.navigator.language;
  if(language === 'es') { window.alert('Hola'); }
   else { window.alert("Hello"); }
}

Padahal, ini bukan cara perpustakaan bekerja. Sebagai gantinya, ia memiliki satu set file yang terlihat seperti:

# English file
greeting = hello
# Spanish file
greeting = hola

Dan kemudian pustaka akan mendeteksi pengaturan bahasa browser dan kemudian membuat fungsi dinamis dengan lokalisasi yang sesuai sebagai nilai balik untuk pemanggilan fungsi tanpa arguemnt berdasarkan pada file lokalisasi yang sesuai.

Saya tidak cukup coder Javascript untuk mengatakan apakah itu baik atau buruk ... hanya itu dan dapat dilihat sebagai pendekatan yang mungkin.

Intinya, membungkus panggilan ke fungsi lain dalam suatu fungsinya sendiri seringkali cukup bermanfaat dan membantu dengan modularisasi aplikasi dan juga dapat menghasilkan kode yang lebih mudah dibaca.

Selain itu, Anda sedang mengerjakan tutorial. Penting untuk memperkenalkan hal-hal sesederhana mungkin di awal. Memperkenalkan panggilan fungsi gaya varargs dari awal dapat menghasilkan beberapa kode yang sangat membingungkan bagi seseorang yang tidak terbiasa dengan pengkodean secara umum. Jauh lebih mudah untuk beralih dari tanpa argumen, ke argumen, ke gaya varargs - dengan masing-masing membangun contoh dan pemahaman sebelumnya.

zzzzBov
sumber
3
window.alertjuga sering digunakan sebagai pengganti selama pengembangan sampai modal / popup yang bagus dapat dirancang / diimplementasikan, jadi, sama seperti masalah bahasa, ia dapat diganti dengan lebih mudah. Atau jika Anda sudah memilikinya, pembaruan desain beberapa tahun ke depan mungkin memerlukan perubahan serupa.
Izkata
34

Saya pikir ini kadang berguna untuk menyembunyikan implementasi.

 function sayHello() {
  window.alert("Hello");
 }

Dan ini memberi Anda fleksibilitas untuk mengubahnya nanti

 function sayHello() {
  console.log("Hello");
 }
Sleiman Jneidi
sumber
19

Selain kebingungan, adakah manfaat menulis sesuatu seperti ini di kehidupan nyata? Jika demikian, apa manfaatnya?

  • sentralisasi: meskipun implementasinya panjang satu baris, jika itu garis yang sering berubah, Anda mungkin lebih suka mengubahnya di satu tempat, daripada di mana pun sayHello dipanggil.

  • meminimalkan / menyembunyikan dependensi: kode klien Anda tidak perlu lagi tahu ada objek jendela, dan Anda bahkan dapat mengubah seluruh implementasi tanpa mempengaruhi kode klien sama sekali

  • pemenuhan kontrak: kode klien dapat mengharapkan modul yang memiliki fungsi sayHello. Dalam hal ini, bahkan jika sepele, maka fungsi harus ada di sana.

  • konsistensi tingkat abstraksi: jika kode klien menggunakan operasi tingkat tinggi, Anda berkepentingan untuk menulis kode klien dalam istilah 'sayHello, sayBye' dan beberapa fungsi 'sayXXX' lainnya, alih-alih objek jendela. Infact, dalam kode klien Anda bahkan mungkin tidak ingin tahu ada yang namanya objek 'jendela'.

utnapistim
sumber
Saya suka jawaban ini. Seringkali desain adalah alasan utama untuk fungsi-fungsi ini, terutama desain OO di mana Anda ingin objek yang bertanggung jawab atas perilaku untuk mengeksekusi fungsi objek lain dengan perilaku tertentu. Gambar mobil Anda, lebih khusus lagi Anda menggeser persneling. Anda menggeser gigi ke atas dengan "memberi tahu" tongkat Anda untuk bergeser ke atas. Pada gilirannya itu meneruskan panggilan ini ke gearbox Anda. Tetapi selain itu cek pertama kali Anda dapat bergeser dari posisi Anda saat ini.
Eric
3
Alasan lainnya bagus tapi +1 untuk menyebutkan level abstraksi. Menggunakan abstraksi yang jelas dan nama fungsi yang baik dapat membuatnya lebih mudah untuk membaca dan memelihara kode lama. Pada titik di mana sayHello () dipanggil, Anda tidak perlu khawatir dengan bagaimana penerapannya, Anda hanya ingin memahami apa maksud dari baris kode ini. Dan nama fungsi seperti sayHello () membuatnya jelas.
kkrambo
Juga +1 untuk menyebutkan level abstraksi: bisa terjadi bahwa implementasi fungsi pada satu level abstraksi terdiri dari satu panggilan ke fungsi lain dari level abstraksi yang lebih rendah. Terus?
Giorgio
7

Luar biasa bahwa tidak ada satu orang pun yang menyebutkan pengujian.

Garis "terbungkus" tertentu yang Anda pilih,, window.alert('hello')sebenarnya adalah contoh sempurna dari ini. Apa pun yang melibatkan windowobjek benar- benar menyakitkan untuk diuji. Lipat gandakan dengan 1000 kali dalam aplikasi Anda dan saya jamin para pengembang pada akhirnya akan menyerah pada pengujian. Di sisi lain, cukup mudah untuk hanya menghancurkan sayHellofungsi dengan mata-mata dan menguji apakah itu dipanggil.

Contoh yang lebih praktis - karena sungguh, siapa yang sebenarnya menggunakan window.alert(...)kode produksi? - sedang memeriksa jam sistem. Jadi misalnya, ini akan menjadi pembungkus DateTime.Nowdi .NET, time(...)di C / C ++, atau System.currentTimeMillis()di Jawa. Anda benar - benar ingin membungkus mereka dalam dependensi yang dapat Anda suntikkan, karena mereka tidak hanya (hampir) tidak mungkin untuk diejek / dipalsukan, mereka hanya baca dan non-deterministik . Setiap tes yang mencakup fungsi atau metode yang membuat penggunaan langsung dari fungsi jam sistem sangat mungkin menderita intermiten dan / atau kegagalan acak.

Wrapper sebenarnya adalah fungsi 1-baris - return DateTime.Now- tetapi hanya itu yang Anda butuhkan untuk mengambil objek yang tidak dirancang dengan baik dan tidak dapat diuji dan menjadikannya objek yang bersih dan dapat diuji. Anda dapat mengganti jam palsu dengan pembungkus, dan mengatur waktunya untuk apa pun yang Anda inginkan. Masalah terpecahkan.

Aaronaught
sumber
2

Seperti yang Doval katakan, contoh ini mungkin hanya mencoba memperkenalkan Anda ke fungsi. Tapi saya umum, ini berguna. Terutama dengan menentukan beberapa tetapi tidak semua argumen, dan melewati yang lain, Anda dapat membuat fungsi yang lebih spesifik kasus dari fungsi yang lebih umum. Sebagai contoh yang agak sepele, pertimbangkan fungsi sortir yang membutuhkan array untuk disortir dan fungsi komparator untuk disortir. Dengan menentukan fungsi komparator yang membandingkan dengan nilai numerik, saya bisa membuat fungsi sortByNumericalValue, dan panggilan ke fungsi itu jauh lebih jelas dan ringkas.

raptortech97
sumber
2

Pemikiran di balik pertanyaan Anda tampaknya adalah: "Mengapa tidak alert("Hello");langsung menulis ? Ini cukup sederhana."

Jawabannya adalah, sebagian, karena Anda tidak benar-benar ingin menelepon alert("Hello")- Anda hanya ingin menyapa.

Atau: Mengapa menyimpan kontak di ponsel Anda, ketika Anda bisa memanggil nomor telepon saja? Karena Anda tidak ingin mengingat semua angka itu; karena memanggil nomor itu membosankan dan rentan kesalahan; karena jumlahnya mungkin berubah, tetapi masih orang yang sama di ujung lainnya. Karena Anda ingin memanggil orang , bukan angka.

Inilah yang dipahami oleh istilah-istilah seperti abstraksi, tipuan, "menyembunyikan detail implementasi", dan bahkan "kode ekspresif."

Alasan yang sama berlaku untuk menggunakan konstanta alih-alih menulis nilai mentah di mana-mana. Anda hanya bisa menulis 3.141592...setiap kali Anda perlu π, tapi untungnya ada Math.PI.

Kita mungkin juga melihat alert()dirinya sendiri. Siapa yang peduli bagaimana ia membangun dan menampilkan dialog peringatan itu? Anda hanya ingin memberi tahu pengguna. Antara Anda menulis alert("Hello")dan piksel pada layar Anda berubah, ada tumpukan kode dan perangkat keras yang dalam, dengan setiap lapisan memberi tahu apa yang diinginkannya berikutnya, dan lapisan berikutnya mengurus perincian sampai lapisan terdalam membalik beberapa bit di memori video.

Anda benar-benar tidak ingin harus melakukan semua itu sendiri hanya untuk menyapa.

Pemrograman - yah, tugas apa pun, sungguh - adalah tentang memecah masalah yang rumit menjadi bagian yang dapat dikelola. Memecahkan setiap bagian memberi Anda blok bangunan, dan dengan blok bangunan yang cukup sederhana, Anda dapat membangun hal-hal besar.

Ini aljabar.

Flambino
sumber
-1

Merupakan ide bagus untuk menjaga agar perhitungan nilai (ekspresi) tidak terpisah dari eksekusi tindakan (pernyataan). Kami ingin kontrol yang tepat atas di mana dan kapan tindakan akan diambil (seperti menampilkan pesan), tetapi ketika menghitung nilai kami lebih suka bekerja pada tingkat yang lebih abstrak dan tidak perlu peduli tentang bagaimana nilai-nilai itu dihitung.

Fungsi yang hanya menghitung nilai balik, hanya menggunakan argumen yang diberikan, disebut murni .

"Fungsi" yang melakukan tindakan sebenarnya adalah prosedur , yang memiliki efek .

Setiap efek yang disebabkan selama perhitungan nilai disebut efek samping , dan lebih baik untuk menghindarinya jika memungkinkan ("Saya hanya membutuhkan string itu, saya tidak tahu itu akan memalu database!").

Untuk meminimalkan kemungkinan efek samping, kita harus menghindari pengiriman terlalu banyak data ke prosedur kita, atau memasukkan perhitungan apa pun ke dalamnya; jika beberapa perhitungan perlu dilakukan sebelumnya, biasanya lebih baik melakukannya secara terpisah dalam fungsi murni, kemudian hanya menyerahkan hasil yang diperlukan untuk prosedur. Ini menjaga tujuan prosedur tetap jelas, dan mengurangi kemungkinan bahwa itu akan digunakan kembali nanti sebagai bagian dari perhitungan (fungsi murni dapat digunakan kembali sebagai gantinya).

Untuk alasan yang sama, kita harus menghindari pemrosesan hasil di dalam suatu prosedur. Lebih baik mengembalikan hasil (jika ada) tindakan kami, dan melakukan pemrosesan selanjutnya dengan fungsi murni.

Jika kita mengikuti aturan ini, kita mungkin berakhir dengan prosedur seperti sayHello, yang tidak memerlukan data apa pun dan tidak memiliki hasil. Oleh karena itu antarmuka terbaik untuk itu adalah tidak memiliki argumen dan tidak mengembalikan nilai. Ini lebih disukai, misalnya, memanggil "console.log" di tengah-tengah beberapa perhitungan.

Untuk mengurangi kebutuhan akan efek selama perhitungan, kita dapat memiliki perhitungan yang mengembalikan prosedur ; misalnya. jika kita perlu memutuskan tindakan yang akan diambil, kita dapat memiliki fungsi murni memilih prosedur dan mengembalikannya, daripada menjalankannya secara langsung.

Demikian juga, untuk mengurangi kebutuhan akan perhitungan selama prosedur, kita dapat meminta prosedur mengambil prosedur lain sebagai parameter (mungkin hasil dari suatu fungsi); misalnya. mengambil berbagai prosedur dan menjalankan satu demi satu.

Warbo
sumber
Anda tampaknya mengadvokasi menentang OOP di sini, di mana prinsip dasarnya adalah "katakan, jangan tanya". Mengikuti saran di sini adalah apa yang biasanya mengarah pada kode yang penuh dengan panggilan "getFoo" yang tidak berguna, "setFoo" dan "eksekusi". OOP adalah tentang menggabungkan data dan perilaku, bukan memisahkannya.
Aaronaught
@Aonaonaught Memang benar saya menentang OOP, tapi saya tentu tidak akan merekomendasikan setFoopanggilan, karena itu menyiratkan data yang bisa berubah. Mengubah isi variabel / properti adalah efek, yang menyebabkan semua perhitungan menggunakan data tersebut menjadi tidak murni. Saya tidak akan merekomendasikan executepanggilan sendiri, tetapi saya akan merekomendasikan runFooprosedur untuk melakukan tindakan berdasarkan argumen mereka.
Warbo
-2

Saya akan mengatakan itu adalah kombinasi dari jawaban yang diberikan oleh @MichaelT dan @Sleiman Jneidi.

Mungkin ada sejumlah tempat dalam kode tempat Anda ingin menyapa pengguna dengan pesan Hello sehingga Anda mengemas ide itu dalam suatu metode. Dalam metode ini Anda dapat menerjemahkannya atau memperluas 'Halo' sederhana dengan menampilkan teks yang lebih panjang. Anda juga mungkin ingin menggunakan dialog JQuery yang bagus sebagai pengganti peringatan.

Intinya adalah implementasinya ada di satu tempat. Anda hanya perlu mengubah kode di satu tempat. (SayHello () mungkin adalah contoh yang terlalu sederhana)

paul
sumber
@downvoter (s) - peduli untuk berbagi pengetahuan Anda dengan kami semua. Apakah posting saya salah, ditulis dengan buruk atau apa?
paul