Skillversitas

Functions in JavaScript

What Is a Function?

A function is a block of code that can be executed repeatedly under a specific name. Functions help us to:

  • Avoid repeating code (DRY — Don't Repeat Yourself)
  • Break problems down into small pieces
  • Make testing and debugging easier
  • Make code more readable

1. Function Declaration

// Syntax: function function_name(parameter) { ... }

function greetStudent(name) {
    console.log(`Welcome, ${name}!`);
}

// Calling the function
greetStudent("John Smith"); // "Welcome, John Smith!"
greetStudent("Mike Brown");  // "Welcome, Mike Brown!"

Function with a Return Value

// Function returning a value
function calcAverage(a, b, c) {
    const average = (a + b + c) / 3;
    return average;
}

const result = calcAverage(85, 90, 78);
console.log(`Average: ${result}`); // "Average: 84.33..."

// Returning an object
function createStudentProfile(studentId, name, gpa) {
    return {
        studentId: studentId,
        name: name,
        gpa: gpa,
        classification: gpa >= 3.5 ? "Cum Laude" : "Non Cum Laude",
        createdAt: new Date().toISOString()
    };
}

const profile = createStudentProfile("2024100123", "John Smith", 3.75);
console.log(profile);

Hoisting

Function declarations are fully hoisted, which means they can be called before they are declared.

// ✅ Can be called before its declaration
console.log(calcCredits(20)); // "Total credits: 20"

function calcCredits(credits) {
    return `Total credits: ${credits}`;
}

2. Function Expression

A function stored in a variable.

// Syntax: const function_name = function(parameter) { ... }

const add = function(a, b) {
    return a + b;
};

console.log(add(10, 5)); // 15

// Not hoisted — must be declared first
// console.log(multiply(3, 4)); // ReferenceError!
const multiply = function(a, b) {
    return a * b;
};

3. Arrow Function (ES6)

A more concise syntax for function expressions.

// Arrow function — one parameter, one statement
const square = x => x * x;
console.log(square(5)); // 25

// Arrow function — multiple parameters
const add = (a, b) => a + b;
console.log(add(10, 5)); // 15

// Arrow function — code block (needs an explicit return)
const determineGrade = (score) => {
    if (score >= 90) return "A";
    if (score >= 80) return "B";
    if (score >= 70) return "C";
    if (score >= 60) return "D";
    return "E";
};

console.log(determineGrade(85)); // "B"

// Arrow function — returning an object literal
const createStudent = (studentId, name) => ({
    studentId: studentId,
    name: name,
    createdAt: new Date()
});

const stu = createStudent("2024100123", "John");
console.log(stu); // { studentId: "2024100123", name: "John", createdAt: ... }

4. Parameters vs Arguments

// Parameters: the variable names in the function declaration
// Arguments: the actual values when the function is called

function sumTotal(score1, score2, score3) { // <- these are parameters
    return score1 + score2 + score3;
}

// 85, 90, 78 are arguments
const total = sumTotal(85, 90, 78);
console.log(total); // 253

// arguments object (only available in function expressions & declarations)
function sumAll() {
    let total = 0;
    for (let i = 0; i < arguments.length; i++) {
        total += arguments[i];
    }
    return total;
}

console.log(sumAll(85, 90, 78, 88, 92)); // 433

5. Default Parameters (ES6)

Provides a default value when a parameter is not passed.

// Default parameters
function createAccount(name, role = "student", status = "active") {
    return {
        name: name,
        role: role,
        status: status,
        createdAt: new Date()
    };
}

console.log(createAccount("John"));
// { name: "John", role: "student", status: "active" }

console.log(createAccount("Mike", "instructor"));
// { name: "Mike", role: "instructor", status: "active" }

console.log(createAccount("Anna", "admin", "inactive"));
// { name: "Anna", role: "admin", status: "inactive" }

// Default parameter with an expression
function createStudentId(name, year = new Date().getFullYear().toString().slice(-2)) {
    const random = Math.floor(Math.random() * 10000).toString().padStart(4, '0');
    return `${year}${random}`;
}

console.log(createStudentId("John")); // "241234" (year + random)

6. Rest Parameters (ES6)

Collects all arguments into an array.

// Rest parameters
function calcAverage(...scores) {
    const total = scores.reduce((sum, n) => sum + n, 0);
    return total / scores.length;
}

console.log(calcAverage(85, 90, 78, 92, 88)); // 86.6
console.log(calcAverage(80, 85)); // 82.5

// Rest parameters alongside regular parameters
function createAnnouncement(title, ...students) {
    console.log(`\n=== ${title} ===`);
    students.forEach((m, i) => {
        console.log(`${i + 1}. ${m}`);
    });
}

createAnnouncement("Top Graduates", "John Smith", "Mike Brown", "Anna Green");
// === Top Graduates ===
// 1. John Smith
// 2. Mike Brown
// 3. Anna Green

7. Callback Functions

A function passed as an argumentt to another function.

// Basic callback
function processData(data, callback) {
    const result = data.map(item => item.toUpperCase());
    callback(result);
}

processData(["john", "mike", "anna"], (result) => {
    console.log(result); // ["JOHN", "MIKE", "ANNA"]
});

// Callback in an academic portal
function fetchStudentData(studentId, onSuccess, onError) {
    // Simulated data retrieval
    const database = {
        "2024100123": { name: "John Smith", gpa: 3.75 },
        "2024100124": { name: "Mike Brown", gpa: 3.50 }
    };

    const data = database[studentId];

    if (data) {
        onSuccess(data);
    } else {
        onError(`No data found for student ID ${studentId}`);
    }
}

// Usage with callbacks
fetchStudentData(
    "2024100123",
    (data) => console.log(`Name: ${data.name}, GPA: ${data.gpa}`),
    (error) => console.error(error)
);

fetchStudentData(
    "2024100999",
    (data) => console.log(`Name: ${data.name}`),
    (error) => console.error(error) // "No data found for student ID 2024100999"
);

8. Immediately Invoked Function Expression (IIFE)

A function that runs immediately when it is declared.

// IIFE
(function() {
    console.log("This is an IIFE — it runs immediately!");
})();

// IIFE with parameters
(function(name) {
    console.log(`Hello, ${name}! This is an IIFE.`);
})("John");

// Arrow function IIFE
(() => {
    console.log("Arrow IIFE!");
})();

// Usage: creating a private scope
const AcademicSystem = (function() {
    // Private variables
    const MAX_CREDITS = 24;
    const MIN_GPA = 2.0;

    // Private function
    function validateCredits(credits) {
        return credits >= 1 && credits <= MAX_CREDITS;
    }

    // Public function
    return {
        enrollInCourse: function(student, course) {
            if (validateCredits(course.credits + student.creditsTaken)) {
                student.courses.push(course);
                student.creditsTaken += course.credits;
                return { success: true, message: "Successfully enrolled in the course" };
            }
            return { success: false, message: `Exceeds the maximum of ${MAX_CREDITS} credits` };
        }
    };
})();

// Usage
const john = { name: "John", creditsTaken: 18, courses: [] };
const result = AcademicSystem.enrollInCourse(john, { code: "IF104", name: "Artificial Intelligence", credits: 3 });
console.log(result); // { success: true, message: "Successfully enrolled in the course" }

9. Pure Functions

A function that always produces the same output for the same input, with no side effects.

// ✅ Pure function
function calcGPA(scoreArray) {
    const total = scoreArray.reduce((sum, n) => sum + n, 0);
    return total / scoreArray.length;
}

console.log(calcGPA([85, 90, 78])); // always 84.33...

// ❌ Impure function (has side effects)
let callCount = 0;

function calcGPAImpure(scoreArray) {
    callCount++; // modifies external state
    const total = scoreArray.reduce((sum, n) => sum + n, 0);
    return total / scoreArray.length;
}

Case Study: Functions for Calculating Student Average Scores

// === STUDENT GRADING SYSTEM ===

// Pure function: calculate the average
function calcAverage(...scores) {
    if (scores.length === 0) return 0;
    const total = scores.reduce((sum, n) => sum + n, 0);
    return Math.round((total / scores.length) * 100) / 100;
}

// Function: determine the grade
function determineGrade(score) {
    if (score >= 90) return { grade: "A", rating: "Excellent" };
    if (score >= 80) return { grade: "B", rating: "Good" };
    if (score >= 70) return { grade: "C", rating: "Fair" };
    if (score >= 60) return { grade: "D", rating: "Poor" };
    return { grade: "E", rating: "Very Poor" };
}

// Function: create a grade report card
function createGradeCard(studentId, name, scoreList) {
    const average = calcAverage(...scoreList);
    const grade = determineGrade(average);

    return {
        studentId: studentId,
        name: name,
        scores: scoreList,
        average: average,
        grade: grade.grade,
        rating: grade.rating,
        passed: average >= 60,
        academicYear: "2024/2025"
    };
}

// Function: display the grade report card
function showGradeCard(card) {
    console.log("\n╔════════════════════════════════════╗");
    console.log("║     STUDENT GRADE REPORT CARD      ║");
    console.log("╠════════════════════════════════════╣");
    console.log(`║ ID     : ${card.studentId.padEnd(24)}║`);
    console.log(`║ Name   : ${card.name.padEnd(24)}║`);
    console.log("╠════════════════════════════════════╣");
    console.log("║ SCORES:                            ║");

    card.scores.forEach((n, i) => {
        console.log(`║   Week ${i + 1}: ${String(n).padStart(3)}                      ║`);
    });

    console.log("╠════════════════════════════════════╣");
    console.log(`║ Average   : ${String(card.average).padEnd(22)}║`);
    console.log(`║ Grade     : ${card.grade.padEnd(22)}║`);
    console.log(`║ Rating    : ${card.rating.padEnd(22)}║`);
    console.log(`║ Status    : ${(card.passed ? "PASS" : "FAIL").padEnd(22)}║`);
    console.log("╚════════════════════════════════════╝");
}

// === USAGE ===

const studentList = [
    { studentId: "2024100123", name: "John Smith",   scores: [85, 90, 78, 88, 92] },
    { studentId: "2024100124", name: "Mike Brown",    scores: [70, 75, 68, 72, 80] },
    { studentId: "2024100125", name: "Anna Green",      scores: [55, 60, 50, 58, 62] }
];

// Process all students
for (const s of studentList) {
    const card = createGradeCard(s.studentId, s.name, s.scores);
    showGradeCard(card);
}

// Class summary
console.log("\n=== CLASS SUMMARY ===");
const classAverage = calcAverage(
    ...studentList.map(m => calcAverage(...m.scores))
);
console.log(`Class average: ${classAverage}`);

Summary

Type Syntax Hoisting Use When
Declaration function name() {} Yes Main functions, utilities
Expression const name = function() {} No Callbacks, conditional branches
Arrow const name = () => {} No Short callbacks, pure functions
IIFE (function() {})() No Private scope, initialization
Default function(a = 1) {} - Optional parameters
Rest function(...args) {} - Variable arguments

Use arrow functions for short callbacks, function declarations for main functions, and default/rest parameters for flexibility.