Skillversitas

Arrow Functions in JavaScript

Arrow functions are a concise syntax for writing functions, introduced in ES6 (2015). Besides being shorter, arrow functions have an important difference from regular functions in how they handle this. Arrow functions are extremely popular as callbacks for array methods such as map, filter, and reduce.


Basic Syntax

// Regular function (traditional)
function count(a, b) {
  return a + b;
}

// Arrow function — full form
const count = (a, b) => {
  return a + b;
};

// Arrow function — implicit return (one line, no curly braces)
const count = (a, b) => a + b;

// Arrow function — one parameter (no parentheses)
const square = x => x * x;

// Arrow function — no parameters
const greet = () => "Welcome!";

// Arrow function — returning an object literal (needs parentheses)
const createStudent = (name, studentId) => ({ name, studentId });

console.log(createStudent("John", "2023001"));
// { name: "John", studentId: "2023001" }

Code Example: Syntax Variations

// Multi-line — must use curly braces and return
const processGrade = (grade) => {
  const bonus = 5;
  const total = grade + bonus;
  return total > 100 ? 100 : total;
};

console.log(processGrade(90)); // 95
console.log(processGrade(98)); // 100

// Nested arrow function
const power = (base) => (exponent) => Math.pow(base, exponent);
const square = power(2);
console.log(square(10)); // 1024

// Array methods with arrow functions
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const even = numbers.filter(n => n % 2 === 0);
console.log(even); // [2, 4, 6, 8, 10]

const squares = numbers.map(n => n * n);
console.log(squares); // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum); // 55

The this Binding Difference

This is the most critical difference between arrow functions and traditional functions.

// === TRADITIONAL FUNCTION ===
// 'this' depends on HOW the function is called (the caller)

const student = {
  name: "John",
  gpa: 3.75,

  // Traditional function — 'this' = the calling object
  greet: function() {
    return `Hello, I am ${this.name}`;
  },

  // ❌ Arrow function as a method — 'this' is NOT the object
  greetWrong: () => {
    return `Hello, I am ${this.name}`; // this = window/global!
  }
};

console.log(student.greet());       // "Hello, I am John" ✅
console.log(student.greetWrong());  // "Hello, I am undefined" ❌
// === ARROW FUNCTION ===
// 'this' refers to the LEXICAL SCOPE (where the function is defined)

class CampusClass {
  constructor() {
    this.student = ["John", "Amy", "Mike"];
  }

  // Arrow function as a class field — this = the CampusClass instance
  showAll = () => {
    return this.student.join(", ");
  };

  // Traditional method — this = the instance when called
  showAllTraditional() {
    return this.student.join(", ");
  }
}

const myClass = new CampusClass();

// setTimeout callback — the arrow function preserves this
setTimeout(() => {
  console.log(myClass.showAll()); // ✅ Works!
}, 1000);

When to Use / Not Use

// ✅ USE ARROW FUNCTIONS FOR:

// 1. Array method callbacks
const grades = [85, 92, 78, 90, 88];
const passing = grades.filter(n => n >= 80);

// 2. Promise/async callbacks
fetchData()
  .then(data => data.json())
  .then(json => console.log(json));

// 3. Functions that do not need this
const multiply = (a, b) => a * b;

// 4. Anonymous functions in arguments
[1, 2, 3].forEach(n => console.log(n * 2));

// ❌ DO NOT USE ARROW FUNCTIONS FOR:

// 1. Object methods
const student = {
  name: "John",
  // ❌ Arrow function
  greet: () => `Hello, I am ${this.name}`, // this = window!
  // ✅ Traditional function or shorthand
  greetCorrect() { return `Hello, I am ${this.name}`; }
};

// 2. Constructor functions
// ❌
const Student = (name) => { this.name = name; }; // this = window!
// ✅
function Student(name) { this.name = name; }

// 3. Event handlers that need this
// ❌ Element.addEventListener("click", () => this); // this = lexical
// ✅ Element.addEventListener("click", function() { this; }); // this = the element

Code Explanation

Aspect Traditional Function Arrow Function
Syntax function(a, b) {} (a, b) => {}
this Determined at call time Lexical (where defined)
arguments object Available Not available
As an object method ✅ this = the object ❌ this = the outer scope
As a callback ✅ ✅ (most popular)
Constructor ✅ ❌

Everyday Case Studies

1. Array Method Callbacks for Student Data

const students = [
  { name: "John", gpa: 3.75, credits: 13, majorCode: "CS" },
  { name: "Amy", gpa: 3.90, credits: 14, majorCode: "SI" },
  { name: "Mike", gpa: 2.80, credits: 12, majorCode: "CS" },
  { name: "Anna", gpa: 3.50, credits: 15, majorCode: "SI" },
  { name: "David", gpa: 3.20, credits: 11, majorCode: "TK" },
  { name: "Mary", gpa: 3.85, credits: 14, majorCode: "CS" },
];

// Filter: students with GPA >= 3.5 (potential cum laude)
const cumLaude = students.filter(student => student.gpa >= 3.5);
console.log("Calon Cum Laude:", cumLaude.map(m => m.name));
// ["John", "Amy", "Anna", "Mary"]

// Map: extract only names and GPAs
const summary = students.map(student => ({
  name: student.name,
  gpa: student.gpa,
  classification: student.gpa >= 3.5 ? "Cum Laude" : "Very Satisfactory"
}));
console.log(summary);

// Reduce: average GPA across all students
const averageGPA = students
  .reduce((acc, student) => acc + student.gpa, 0) / students.length;
console.log(`Average GPA: ${averageGPA.toFixed(2)}`);

// Chaining: filter → map → sort
const ranking = students
  .filter(student => student.credits >= 13)
  .sort((a, b) => b.gpa - a.gpa)
  .map((student, i) => `${i + 1}. ${student.name} (${student.gpa})`);

console.log("Ranking credits ≥ 13:");
ranking.forEach(r => console.log(r));

2. Form Input Processing

// Simulated event handler with an arrow function
const formValues = {
  name: "John Smith",
  email: "[email protected]",
  midTermGrade: "85",
  finalGrade: "90"
};

// Transform values — the arrow function as a callback
const processForm = (input) => {
  return Object.entries(input).reduce((acc, [key, value]) => {
    // Auto-convert numbers
    if (/^\d+\.?\d*$/.test(value)) {
      acc[key] = parseFloat(value);
    } else {
      acc[key] = value;
    }
    return acc;
  }, {});
};

const processed = processForm(formValues);
console.log(processed);
// { name: "John Smith", email: "[email protected]", midTermGrade: 85, finalGrade: 90 }

3. Dynamic Sorting

const courseList = [
  { name: "Algorithms", credits: 3, semester: 2 },
  { name: "Web Dev", credits: 4, semester: 3 },
  { name: "Database", credits: 3, semester: 2 },
  { name: "Artificial Intelligence", credits: 3, semester: 5 },
  { name: "Networking", credits: 4, semester: 4 },
];

// Dynamic sorting with an arrow function
const sortBy = (field, direction = "asc") => {
  return (arr) => [...arr].sort((a, b) => {
    const valA = a[field];
    const valB = b[field];
    const modifier = direction === "asc" ? 1 : -1;
    return valA > valB ? modifier : valA < valB ? -modifier : 0;
  });
};

const byCredits = sortBy("credits", "desc")(courseList);
console.log("By credits (desc):", byCredits.map(m => `${m.name} (${m.credits} credits)`));

const bySemester = sortBy("semester", "asc")(courseList);
console.log("By Semester:", bySemester.map(m => `${m.name} (Sem ${m.semester})`));

Conclusion

  • Arrow functions use the concise (params) => expression syntax instead of function.
  • Implicit return is automatic for a single expression — no return or curly braces {} needed.
  • this binding differs: arrow functions use the lexical scope (where they are defined), not the caller.
  • Extremely ideal as callbacks for map(), filter(), reduce(), forEach(), and Promises.
  • Do not use them as object methods, constructors, or event handlers that need this.
  • To return an object literal from an arrow function, wrap it in parentheses: () => ({...}).