10 Functions

Fungsi merupakan suatu bentuk abstraksi untuk mewakili proses yang menghubungkan input dan output. Beberapa bahas pemrograman lain yang cukup lama seperti C, C++, dan Fortran, menyebuh fungsi sebagai subroutine atau procedure.

Maksud dari proses abstraksi tersebut adalah, dengan menggunakan fungsi kita bisa mewakili suatu prosedur yang panjang dan dipakai berulang dan menamakan prosedur tersebut sebagai suatu fungsi. Hal ini tentunya akan mempermudah pekerjaan kita, ketika kita dihadapkan dengan masalah yang hampir serupa, dan kita cukup menggunakan (memanggil) fungsi tersebut tanpa harus mengetik berulang-ulang proses yang diwakili fungsi tersebut.

Kemampuan berabstraski sangat diperlukan untuk bisa menyusun fungsi yang benar dan efisien. Pembuatan fungsi dimulai dengan menuliskan prosedur secara modular (terpisah-pisah), setelah terlihat strukturnya kita bisa menggabungkan prosedur tersebut ke dalam suatu fungsi.

Dengan fungsi, kita juga dapat mengimplementasi berbagai macam algoritma-algoritma pemecahan masalah. Di akhir pertemuan tentang fungsi ini, kita akan mencoba untuk menyusun algoritma sederhana

Beberapa hal yang akan kita pelajari di sesi ini adalah: 1. Istilah-istilah dasar dalam fungsi 2. Cara mendeklarasikan fungsi 3. Pemanggilan fungsi 4. a brief intro to functional programming

10.1 Some basics terminology in JavaScript's function

  • Invoked: merupakan peristiwa saat kita memanggil fungsi yang telah didefinisikan

  • parameterized: keadaan suatu variable input atau variabel yang dimuat oleh suatu fungsi bersifat lokal (telah terparameterisasi)

  • parameter: variable input yang dimiliki oleh fungsi yang berfungsi sebagai penanda (identifier)

  • argument: merupakan nilai yang akan diinputkan ke dalam fungsi atau nilai yang diberikan ke variabel input. Proses pemberian argument terjadi saat fungsi dipanggil (function invocation)

  • method: fungsi yang secara khusus didefinisikan sebagai property suatu object

  • constructor: fungsi yang secara khusus didefinisikan untuk melakukan pendeklarasian suatu object.

  • closure: merupakan sifat dari fungsi di JavaScript yang mana suatu definisi fungsi dapat disisipkan dalam suatu fungsi lain dan fungsi yang didefinisikan tersebut dapat mengakses variable di fungsi yang disisipi.

10.2 Function declaration

  • menggunakan kata kunci function

    func-def-with-function.js

    // Mencetak `property name` dan `property value` dari suatu object o
    function printops(o) {
      for (let p in o) {
        console.log(`${p}: ${o[p]}`);
      }
    }
    
    
    // Melakukan penghitungan jarak antara dua titik (x1, y1) dan (x2, y2)
    function distance(x1, y1, x2, y2) {
      let dx = x2 - x1;
      let dy = y2 - y1;
      return Math.sqrt(dx*dx + dy*dy);
    }
    
    // FUngsi rekursif yang memanggil dirisnya sendiri dan digunakan untuk 
    // menghitung faktorial
    function factorial(x) {
      if (x <= 1) return 1;
      return x * factorial(x-1);
    }
    
    let o = {"apple": 5000, "mango": 7000, "pineapple": 15000};
    printops(o);
    
    console.log();
    let dist = distance(0, 0, 5, 12);  // => 13 = sqrt(5^2 + 12^2)
    console.log("dist: ", dist);
    
    
    console.log();
    console.log("factorial(5): ", factorial(5));   // => 120 = 5 x 4 x 3 x 2 x 1
  • variable yang bernilai suatu function expression

    func-def-with-func-expression.js

    // Function expression berikut mendefinisikan nilai kuadrat dari argument
    // yang diberikan kepada fungsi tersebut
    const square = function(x) { return x*x; };
    console.log(square(5));
    
    // Function expression dapat memuat nama yang dapt digunakan
    // untuk mendefinisikan fungsi rekursif
    const f = function fact(x) { if  (x <= 1) return 1; else return x*fact(x-1); };
    console.log(f(5));
    
    
    // Function expression dapat digunakan sebagai suatu argumen untuk fungsi
    // yang lain
    let result = [3, 2, 1].sort(function(a, b) { return a - b; });
    console.log(result);
    
    // Function expression dapat juga didefinisikan dan langsung di panggil
    // dengan nilai argument
    let tensquared = (function(x) { return x*x; }(10));
    console.log(tensquared);
  • Jalan pintas (shortcut) untuk mendefinisikan fungsi: arrow function

    func-def-with-arrow-func.js

    let result;
    
    // Mendefinisikan fungsi jumlahan dua buat variabel x dan y menggunakan arrow
    // function ( () => {} )
    const sum = (x, y) => { return x + y; };
    result = sum(25, 75);
    console.log(result);
    
    // Tanpa kurung kurawal dan kata kunci `return`
    const sumShort = (x, y) => x + y;
    result = sumShort(25, 75);
    console.log(result);
    
    // Untuk arrow function dengan satu parameter tidak perlu menggunakan kurung
    const polynomial = x => x*x + 2*x + 3;
    result = polynomial(1);
    console.log(result);
    
    
    // Untuk arrow function tanpa argumen dapat menggunakan kurung saja
    const greeting = () => "Hi!";
    result = greeting();
    console.log(result);
    
    // -- Penggunaan arrow function sebagai argument suatu array method
    // Digunakan untuk menghapus element yang bernilai null
    let filtered = [1, null, 2, 3].filter(x => x !== null);
    console.log(filtered);
    
    // Digunakan untuk melakukan kuadrat setiap element array tanpa harus
    // melakukan perulangan menggunakan array method `map()`
    let squares = [1, 2, 3, 4].map(x => x*x);
    console.log(squares);
  • Fungsi yang memuat fungsi (nested function)

    func-def-with-nested-func.js

    // Fungsi berikut akan menghitung sisi miring dari suatu segitiga siku-siku
    // dengan diberikan panjang sisi tegak dan sisi mendatar.
    // Fungsi yang memuat definisi suatu fungsi (square). Disini fungsi square
    // dapat memanggil variabel tempat fungsi tersebut didefinisikan, yaitu
    // dapat mengakses variabel a dan b dari fungsi hypotenuse
    function hypotenuse(a, b) {
      function square(x) { return x*x; }
      return Math.sqrt(square(a) + square(b));
    }
    
    let result = hypotenuse(5, 12);
    console.log(result);

10.3 Function invocation

  • fungsi dipanggil sebagai fungsi
    Pada bagian sebelumnya kita secara tidak langsung sudah melakukan pemanggilan fungsi, yaitu menggunakan nama fungsi dan dikuti kurung buka lalu daftar arguments diakhiri dengan kurung tutup.

  • fungsi dipanggil sebagai method
    Suatu fungsi yang didefinisikan di dalam suatu object dapat dipanggil sebagai suatu methods

    func-invoke-with-method.js

    // Object calculator yang dapat menyimpan input penjumlahan dan hasil 
    // penjumlahannya
    let calculator = {
      operand1: 1,
      operand2: 1,
    
      add() {
        this.result = this.operand1 + this.operand2
      }
    }
    
    // Kita berikan input bilangan yang akan dilakukan penjumlahan
    calculator.operand1 = 5;
    calculator.operand2 = 7;
    
    // Lakukan proses penjumlahan setelah memasukan inpuit
    calculator.add();
    
    // Tampilkan hasil penjumlahan
    console.log(calculator.result);
  • pemanggilan fungsi secara tidak langsung menggunakan call() dan apply()

    func-invoke-with-call-and-apply.js

    let arrayOfNumbers = [4, 2, 3, 1, 1, 2, 3, 5, 1, 3, 3];
    let biggest;
    
    // Pemanggilan fungsi Math.max secara langsung
    biggest = Math.max(...arrayOfNumbers)
    console.log(biggest);
    
    // Kita menggunakan Math object (object bawaan dari JavaScript)
    // yng memuat semua type bilangan. Kita terapkan fungsi Math.max
    // ke arrayOfNumber tetapi secara tidak langsung menggunakkan .appyly
    // Math.max akan menjadi method dari Math object dan juga arrayNumbers
    // akan menjadi argument dari Math.max dan kita tidak perlu melakukan 
    // unpack menggunakan spread operator 
    biggest = Math.max.apply(Math, arrayOfNumbers)
    console.log(biggest);
    
    // with .call you have to use spread operator to unpack the elements
    biggest = Math.max.call(Math, ...arrayOfNumbers);
    console.log(biggest);

10.4 Function arguments and parameters

Di bagian ini kita akan mempelajari bagaimana suatu arguments digunakan dalam suatu fungsi.

  • Optional parameters dan default parameters
    Di bagian ini kita akan melihat bagaimana optional parameter dan default parameters. diimplementasikan ke dalam suatu fungsi. Optional parameters disini berarti kita bisa inputkan argument atau tidak ke optional parameters tersebut

    optional-params.js

    // Fungsi berikut akan mengambil property name dari parameter obj
    // dan menambahkan setiap property name ke dalam parameter arr.
    function getPropertyNames(obj, arr) {
      // Apabila parameter arr tidak digunakan, maka didefinisikan dengan 
      // nilai arr = []  (empty array)
      if (arr === undefined) {
        arr = [];
      }
    
      // Menambahkan setiap property name dari parameter obj ke parameter arr
      for (let property in obj) {
        arr.push(property);
      }
    
      return arr;
    }
    
    // Object berikut menggambarkan konfigurasi laman website yang diambil 
    // dari berkas .css 
    let obj = {
      'max-width': '36rem',
      'padding': ['0', '1rem'],
      'margin': ['3rem', 'auto', '6rem']
    };
    let arr = ['display'];      // konfigurasi lain yang hanya memuat property name
    
    
    // Pemanggilan fungsi pengumpulan property names dari parameters obj
    // namun tanpa parameters arr (parameter arr disini opsional)
    let objPropNames = getPropertyNames(obj);
    console.log(objPropNames);    // => ['max-width', 'padding', 'margin']
    
    // Pemanggilan fungsi pengumpulan property names dari parameter obj
    // dengan optional parameter arr yang telah terisi element 'display'
    let objPropNamesWithOption = getPropertyNames(obj, arr);
    console.log(objPropNamesWithOption);

    Menurut contoh di atas, kita bisa input-kan arr sebagai optional parameter. Jika kita tidak berikan input arr ke optional parameter (parameter urutan kedua), maka secara otomatis fungsi akan mendeklarasikan parameter arr sebagai empty array.

    Berikutnya adalah contoh fungsi dengan default parameter

    default-params.js

    function getPropertyNames02(obj, arr=[]) {
      for (let property in obj) {
        arr.push(property);
      }
    
      return arr;
    }
    
    // Object berikut menggambarkan konfigurasi laman website yang diambil 
    // dari berkas .css 
    let obj = {
      'max-width': '36rem',
      'padding': ['0', '1rem'],
      'margin': ['3rem', 'auto', '6rem']
    };
    let arr = ['display'];      // konfigurasi lain yang hanya memuat property name
    
    
    // Pemanggilan fungsi pengumpulan property names dari parameters obj
    // namun tanpa parameters arr (parameter arr disini akan diset secara 
    // otomatis sebagai array kosong)
    let objPropNames = getPropertyNames(obj);
    console.log(objPropNames);    // => ['max-width', 'padding', 'margin']
    
    // Pemanggilan fungsi pengumpulan property names dari parameter obj
    // dengan default parameter arr yang telah terisi element 'display'
    let objPropNamesWithOption = getPropertyNames(obj, arr);
    console.log(objPropNamesWithOption);

    Terlihat dengan menggunakan default parameter, deklarasi fungsi lebih ringkas dan mudah dimengerti bahwa ketika parameters arr tidak diberikan sebagai argument dalam pemanggilan fungsi, maka secara default akan diberikan nilai awalan empty array.

  • Rest paramaters
    Ketika jumlah argument yang harus kita berikan dalam suatu fungsi saat fungsi tersebut dipanggil ((invocation)) sangat banyak, maka rest parameters dapat membantu kita tanpa perlu meng-inputkan satu-satu. Bayangkan jika jumlah argument suatu fungsi yang dipanggil sejumlah satu juta arguments.

    Berikut contoh penggunaan rest parameters untuk fungsi pencarian nilai maksimum;

    rest-params-max-func.js

    // Fungsi untuk menghitung nilai maksimumn. Terlihat disini digunakan 
    // rest parameters yang diawali oleh tiga titik.
    // Output dari fungsi ini adalah nilai maksimum dari inputan yang diberikan
    function max(...rest) {
      let maxValue = -Infinity;  
      for (let n of rest) {
        if (n > maxValue) {
          maxValue = n;
        }
      }
    
      // Return the biggest
      return maxValue
    }
    
    // Disini kita memberikan input arguments lebih dari satu, namun
    // di dalam pendeklarasian fungsi kita hanya cukup menggunakan rest 
    // parameter menggunakan ...rest
    let result = max(1, 10, 100, 2, 3, 1000, 4, 5, 6);
    console.log(result);
  • Spread operator untuk argument fungsi yang dipanggil/invoked
    Ketika input argument yang disisipkan lebih dari satu ataupun banyak, misalnya 20 arguments, cara yang paling efisien adalah menggunakan spread operator di arguments (ingat kembali perbedaan arguments dan parameters). Berikut ini adalah pemanggilan fungsi menggunakan spread operator untuk input arguments lebih dari satu. Contoh fungsi yang digunakan tetap sama yaitu menghitung nilai maksimum

    spread-op-max-func.js

    function max(...rest) {
      let maxValue = -Infinity;  
      for (let n of rest) {
        if (n > maxValue) {
          maxValue = n;
        }
      }
    
      // Return the biggest
      return maxValue
    }
    
    let inputArr = [1, 10, 100, 2, 3, 1000, 4, 5, 6];
    let result = max(...inputArr)   // Disini kita menggunakan spread operator
                                    // pada argument inputArr
    console.log(result);

10.5 Function as values

Karena fleksibiltas fungsi, kita dapat menggunakan fungsi sebagai suatu nilai.

  • Pengunaan fungsi sebagai nilai suatu variable
    Pada pertemuan sebelumnya di bagian pendeklarasian fungsi, kita telah mengetahui bahwa fungsi dapat di-assign ke suatu variable. Jika yang kita assign adalah nama fungsinya saja, tanpa arguments maka yang terjadi adalah kita membuat referensi baru ke fungsi itu dengan nama variable tersebut.

    func-as-vals-variable-assign.js

    // Berikut adalah fungsi untuk melakukan pengkuadratan
    function square(x) { return x*x; }
    
    // Kita assign fungsi tersebut (tanpa argument) ke variable s
    let s = square;
    
    // Kita dapat memanggil fungsi tersebut (invocation) dengan nama fungsi square
    // atau dengan variable s
    console.log(square(16));
    console.log(s(16));
  • Penggunaan fungsi sebagai nilai dari suatu property
    Sedikit berbeda pada pertemuan sebelumnya yang menggunakan fungsi sebagai method suatu object. Di bagian ini kita dapat memberikan nilai suatu property* dengan suatu fungsi. Property dari object tersebut akan beralih fungsi sebagai nama fungsi atau bisa juga dilihat sebagai method dari object tersebut.

    func-as-vals-props-vals.js

    // DIsini obj memiliki property square dengan nilai adalah
    // fungsi pengkuadratan. Pemanggilan property *square* secara tidak
    // langsung serupa dengan pemanggilan method suatu object
    let obj = { square: function(x) { return x*x; } };
    
    console.log(obj.square(16));
  • Penggunaan fungsi sebagai nilai untuk element suatu array
    Di bagian ini hanyalah sedikit kemungkinan penerapan tidak umum dari fungsi yang digunakan sebagai element suatu array. Disini hanya ditambahkan sebagai kemungkinan bahwa kita dapat mengkonstruksi berbagai macam hal dengan fungsi sekalipun terlihat aneh

    func-as-vals-arr-element.js

    // Fungsi dideklarasikan sebagai element pertama dari arr, lalu nilai
    // argumentnya dapat diambil dari element kedua dari arr
    let arr = [function(x) => { return x * x; }, 16]
    console.log(arr[0](arr[1]));
  • Penggunaan fungsi sebagai nilai untuk argument fungsi lain
    Penggunaan ini adalah yang paling sering digunakan dalam penyusunan program menggunakan JavaScript. Disini fungsi dijadikan sebagai argument untuk nilai parameter suatu fungsi yang lain. Sebagai contoh kita akan membuat suatu program kalkulator yang mana fungsi-fungsi aritmatik seperti kali, bagi, tambah, kurang akan menjadi input argument ke dalam fungsi kalkulator

    func-as-vals-input-args.js

    // Kita definisikan fungsi aritmatika dari fungsi kalkulator
    function add(x, y) { return x + y; }
    function subtract(x, y) { return x - y; }
    function multiply(x, y) { return x * y; }
    function divide(x, y) { return x / y; }
    
    // Berikut adalah fungsi yang mendefinisikan kalkulator
    function calculate(operator, operand1, operand2) {
      return operator(operand1, operand2);
    }
    
    // Menghitung nilai ekspresi  (1 + 2) * (3 - 2) / 3;
    let result = calculate(
      divide, 
      calculate(
        multiply, 
        calculate(
          add, 1, 2), 
        calculate(
          subtract, 3, 2)), 
      3);
    console.log(result);

    Pada program di atas kita melihat bahwa argument kedua dan ketiga saat proses pembagian (divide), merupakan pemanggilan fungsi calculate. Sampai pada akhirnya pada level operasi terdalam (yang memiliki kurung, yaitu penjumlahan dan pengurangan). Fungsi aritmatika: add, subtract, multiply, dan divide digunakan sebagai input argument fungsi calculate. Demikian juga fungsi calculate digunakan sebagai input arguments fungsi calculate

10.6 Functional programming

Dibagian ini kita hanya menyentuh permukaan dari paradigma functional programming. Disini kita hanya menerapkan aplikasi functional programming untuk memproses arrays

Berikut adalah implementasi perhitungan standard deviasi menggunakan looping. Secara singkat, standard deviasi mengukur seberapa jauh distribusi data terhadap nilai rata-rata.

compute-stddev-conventional.js

const formatStr = require('@stdlib/string-format')

let data = [1, 1, 3, 3, 5, 7, 7, 9, 9];

// Menghitung rata-rata dengan cara menjumlahkan semua element
// dan membaginya dengan banyaknya element
let total = 0;
for (let i = 0; i < data.length; i++) {
  total += data[i];
}
let mean = total / data.length;

// Menghitung standard deviasi, pertama menghitung jumlahan
// kuadrat deviasi setiap element terhadap rata-rata.
// Setelah itu di bagi dengan (jumlah data - 1)
total = 0;
for (let i = 0; i < data.length; i++) {
  let deviation = data[i] - mean;
  total += deviation * deviation;
}
let stddev = Math.sqrt(total/(data.length - 1));
console.log(formatStr('%.2f', stddev));     // => 3.16

Berikut ini adalah implementasi program di atas menggunakan paradigma fungsional. Disini kita lihat tidak ada control structure loop lagi, dan semuanya diganti menjadi fungsi map dan reduce. Kita akan menjelaskan lebih detail di sesi kelas terkait map dan reduce.

compute-stddev-func-prog.js

const formatStr = require("@stdlib/string-format");

const map = function(a, ...args) { return a.map(...args); };
const reduce = function(a, ...args) { return a.reduce(...args); };

const sum = (x, y) => x + y;
const square = x => x * x;

let data = [1, 1, 3, 3, 5, 7, 7, 9, 9];
let mean = reduce(data, sum)/data.length;
let deviations = map(data, x => x - mean);
let stddev = Math.sqrt(
  reduce(map(deviations, square), sum)/(data.length - 1));
console.log(formatStr("%.2f", stddev));   // => 3.16

Exercises

  1. Sebutkan 3 kegiatan yang kalian lakukan sehari-hari yang dapat diubah menjadi suatu fungsi. Implementasi fungsi tersebut kedalam JavaScript. Berikan juga contoh penggunaannya.

    Berikut contoh salah satu kegiatan yang mungkin.

    // Berikut adalah fungsi untuk menggambarkan kegiatan makan
    function angkatSendok(n) {
      for (let i = 0; i < n; i++>) {
        console.log(`mengangkat sendok yang ke-${i+1} kali`);
      }
    }
    
    angkatSendok(4);
  2. Buatlah suatu fungsi untuk mengkonversi suatu bilangan ke bentuk string yang merupakan pembacaan bilangan tersebut:

    • 1, menjadi ‘satu’,
    • 2, menjadi ‘dua’,
    • 3, menjadi ‘tiga’,
    • 4, menjadi ‘empat’,
    • 5, menjadi ‘lima’,
    • dst.

    Fungsi yang akan kalian buat tersebut harus mampu mengkonversi hingga bilangan ke-100.

  3. Buatlah sebuah fungsi untuk menghitung besar pengeluaran Yasuke (lihat slide di pertemuan tentang Object) diberikan input weekly expense Yasuke selama seminggu.

    Berikut data weekly expense Yasuke selama seminggu.

    Monday, March 21:
    * Breakfast at a local food stall - 20,000
    * Transportation to work - 10,000
    * Lunch with colleagues - 50,000
    * Snacks from a convenience store - 15,000
    * Dinner at home - 30,000
    
    Tuesday, March 22:
    * Breakfast at home - 10,000
    * Coffee from a cafe - 25,000
    * Groceries for the week - 150,000
    * Lunch from a food delivery app - 35,000
    * Snack from a street vendor - 10,000
    
    Wednesday, March 23:
    * Breakfast at home - 10,000
    * Transportation to work - 10,000
    * Lunch from a food court - 40,000
    * Afternoon tea from a bakery - 20,000
    * Dinner at home - 40,000
    
    Thursday, March 24:
    * Breakfast at home - 10,000
    * Coffee from a cafe - 25,000
    * Transportation to work - 10,000
    * Lunch from a food delivery app - 35,000
    * Snacks from a convenience store - 10,000
    * Dinner at home - 40,000
    
    Friday, March 25:
    * Breakfast at home - 10,000
    * Transportation to work - 10,000
    * Lunch from a food court - 40,000
    * Afternoon snack from a street vendor - 15,000
    * Dinner at a friend's house - 0 (free)
    
    Saturday, March 26:
    * Brunch with friends at a cafe - 80,000
    * Transportation to a shopping mall - 20,000
    * Shopping for clothes and accessories - 300,000
    * Dinner at home - 50,000
    
    Sunday, March 27:
    * Breakfast at home - 10,000
    * Transportation to a park - 15,000
    * Entrance fee to the park - 5,000
    * Lunch from a food stall at the park - 30,000
    * Snacks and drinks from a vending machine - 10,000
    * Dinner at home - 40,000

    Fungsi yang dibuat juga harus mampu menghitung rata-rata pengeluaran harian dari Yasuke.