Viết Hàm JavaScript An Toàn Hơn với Default Parameters

Default parameters trong JavaScript giúp mã ngắn gọn hơn và hạn chế lỗi khi tham số không được truyền vào. Kỹ thuật này đặc biệt hữu ích khi xây dựng hàm phức tạp hoặc xử lý nhiều tham số từ người dùng.

Bài viết này sẽ giúp bạn hiểu rõ default parameters, tránh lỗi undefined, và áp dụng hiệu quả trong dự án thực tế.

#1. Default Parameters là gì?

Default parameters là tính năng cho phép bạn gán giá trị mặc định cho tham số của hàm. Khi hàm được gọi mà không truyền vào đủ tham số, giá trị mặc định sẽ được sử dụng thay vì để chúng là undefined. Điều này làm cho mã trở nên dễ đọc, dễ bảo trì, và giảm số dòng code phải kiểm tra điều kiện.

#1.1. Cú pháp cơ bản

Trước khi default parameters xuất hiện (từ ES6 trở lên), bạn thường phải viết:

1
2
3
4
5
6
7
8
function greet(name) {
  if (!name) {
    name = 'Guest';
  }
  console.log('Hello ' + name);
}

greet(); // Kết quả: "Hello Guest"

Với default parameters, bạn có thể đơn giản hóa:

1
2
3
4
5
function greet(name = 'Guest') {
  console.log(`Hello ${name}`);
}

greet(); // Kết quả: "Hello Guest"

Ở đây, giá trị ‘Guest’ được dùng làm mặc định khi hàm không nhận được tham số nào.

#1.2. Ví dụ nâng cao

Giả sử bạn có một hàm test với hai tham số, một là tên, hai là hàm chào:

1
2
3
4
5
6
function test(name = 'Andy', welcome = () => { return `Hi ${name}`; }) {
  return welcome();
}

console.log(test());          // Kết quả: "Hi Andy"
console.log(test('Brian'));   // Kết quả: "Hi Brian"

#Ý nghĩa

Trong ví dụ trên, nếu bạn không truyền vào tham số name hay welcome, chúng sẽ tự nhận giá trị mặc định là 'Andy' và hàm () => { return "Hi Andy" }. Điều này giúp bạn kiểm soát và đảm bảo chương trình luôn chạy đúng, ngay cả khi người dùng không cung cấp đầy đủ thông tin.

#2. Lợi ích và Ứng dụng Thực tế

#2.1. Giảm thiểu Lỗi Thường Gặp

Một trong những lỗi phổ biến là quên truyền tham số, dẫn đến undefined. Điều này dễ gây ra các lỗi logic hoặc ngoại lệ. Với default parameters, bạn hạn chế đáng kể các trường hợp này:

1
2
3
4
5
6
function calculatePrice(price, tax = 0.1) {
  return price + price * tax;
}

console.log(calculatePrice(100)); // Kết quả: 110
// Không cần kiểm tra if (!tax) vì tax đã có giá trị mặc định.

#2.2. Dễ Dàng Mở Rộng và Bảo Trì Mã

Khi mở rộng một hàm với nhiều tham số mới, bạn có thể đưa ra giá trị mặc định giúp không phá vỡ mã cũ. Điều này hữu ích trong các dự án lớn, khi nhiều lập trình viên làm việc cùng nhau và cần đảm bảo tính tương thích ngược.

#3. Những Lỗi Phổ Biến và Cách Khắc Phục

#3.1. Thiếu Giá trị Mặc định

Nếu bạn quên đặt giá trị mặc định, hàm có thể trả về kết quả không mong đợi:

1
2
3
4
5
function printMessage(message) {
  console.log(`Message: ${message}`);
}

printMessage(); // Kết quả: "Message: undefined"

Cách khắc phục:

1
2
3
4
5
function printMessage(message = 'No Data') {
  console.log(`Message: ${message}`);
}

printMessage(); // Kết quả: "Message: No Data"

#3.2. Phòng Tránh Vòng Lặp Vô Hạn

#Ví dụ

Nếu bạn viết một hàm đệ quy mà quên gán giá trị mặc định hoặc quên kiểm tra điều kiện dừng, bạn có thể vô tình tạo ra vòng lặp vô hạn:

1
2
3
4
5
6
7
8
9
10
function countdown(num = 3) {
  if (num <= 0) {
    return 'Done!';
  }
  console.log(num);
  return countdown(num - 1);
}

console.log(countdown());
// Kết quả: 3, 2, 1, "Done!"

Ở đây, default parameters kết hợp với logic kiểm tra điều kiện giúp tránh vô hạn. Nếu không cẩn thận, thiếu điều kiện dừng có thể dẫn đến lỗi stack overflow.

#3.3. Lỗi Liên Quan đến Phạm vi Biến (Scope) và Execution Context

Khi sử dụng hàm làm giá trị mặc định, bạn cần hiểu Execution Context (ngữ cảnh thực thi) và Call Stack (ngăn xếp lời gọi hàm). Nếu hàm mặc định tham chiếu đến biến bên ngoài không đúng cách, có thể gây ra lỗi logic khó phát hiện:

1
2
3
4
5
6
7
8
9
let globalName = 'Global';

function demo(name = globalName) {
  return `Hello ${name}`;
}

console.log(demo()); // Kết quả: "Hello Global"
globalName = 'Changed';
console.log(demo()); // Kết quả: "Hello Changed"

Trong trường hợp này, giá trị mặc định được đánh giá tại thời điểm thực thi hàm, do đó việc hiểu Execution Context và Call Stack giúp bạn dự đoán được kết quả cuối cùng.

#4. Các Tình Huống Ứng Dụng trong Dự Án Thực Tế

#4.1. Tối Ưu Hàm Xử Lý API

Khi gọi các API, đôi khi bạn không nhận được tất cả các dữ liệu cần thiết. Default parameters giúp đảm bảo hàm xử lý dữ liệu từ API không bị “gãy”:

1
2
3
4
5
6
function formatUser(userData = {name: 'Unknown', age: 0}) {
  return `${userData.name}, ${userData.age} tuổi`;
}

// Kết quả khi không có dữ liệu: "Unknown, 0 tuổi"
console.log(formatUser());

#4.2. Phòng tránh vòng lặp vô hạn

Như đã đề cập, việc kết hợp default parameters với kiểm tra điều kiện dừng trong hàm đệ quy giúp bạn tránh vòng lặp vô hạn, giảm thiểu nguy cơ khiến chương trình bị treo.

Vậy là bạn đã hiểu cách sử dụng default parameters để tối ưu mã JavaScript. Trong thực tế, kỹ thuật này giúp giảm lỗi undefined, dễ bảo trì và mở rộng dự án hơn. Hãy áp dụng vào các hàm của bạn nhé!