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

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

Hướng dẫn Default Parameters: viết hàm an toàn, tránh lỗi undefined, giảm bug và code ngắn gọn hơn trong JavaScript

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 cho phép bạn gán sẵn một giá trị mặc định cho tham số của hàm. Khi ai đó gọi hàm mà bỏ trống tham số đó, hàm sẽ dùng giá trị mặc định thay vì nhận về undefined. Nhờ vậy, bạn không phải viết thêm các dòng kiểm tra điều kiện, và code cũng gọn gàng, dễ đọc hơ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.

Lưu ý

Hai cách viết trên không hoàn toàn giống nhau. Giá trị mặc định chỉ được dùng khi đối số là undefined — tức là bạn không truyền gì, hoặc truyền thẳng undefined. Với null hay các giá trị falsy khác như '', 0, false, hàm vẫn giữ nguyên giá trị đó chứ không thay bằng mặc định:

1
2
3
greet(undefined); // Kết quả: "Hello Guest"
greet(null);      // Kết quả: "Hello null"
greet('');        // Kết quả: "Hello "

Ngược lại, cách viết if (!name) sẽ đổi mọi giá trị falsy ('', 0, null, false) thành 'Guest'. Hai cách xử lý khác nhau, nên khi bạn chuyển từ if (!name) sang default parameters, hàm có thể chạy ra kết quả khác trước. Nếu vẫn muốn dùng giá trị mặc định cho cả trường hợp null, hãy thêm toán tử nullish coalescing ?? bên trong hàm: name = name ?? 'Guest'.

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. Lưu ý rằng gán giá trị mặc định cho cả object không giúp hàm an toàn hơn: nếu API trả về object thiếu thuộc tính (ví dụ {name: 'An'}), default parameter không kích hoạt và các thuộc tính còn thiếu vẫn là undefined. Thay vào đó, hãy kết hợp destructuring với giá trị mặc định cho từng thuộc tính:

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

console.log(formatUser());             // Kết quả: "Unknown, 0 tuổi"
console.log(formatUser({name: 'An'})); // Kết quả: "An, 0 tuổi"

Lưu ý

Nếu API có thể trả về null, bạn cần chuẩn hóa dữ liệu ở phía gọi hàm, ví dụ formatUser(data ?? {}) — vì destructuring null cũng ném ra TypeError (default parameters chỉ kích hoạt khi giá trị là undefined).

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é!

← Previous
Asynchronous JavaScript Và Macro Task Queue: Hiệu Suất Thực Tế
Table of Contents
  1. 1. Default Parameters là gì?
    1. 1.1. Cú pháp cơ bản
    2. 1.2. Ví dụ nâng cao
  2. 2. Lợi ích và Ứng dụng Thực tế
    1. 2.1. Giảm thiểu Lỗi Thường Gặp
    2. 2.2. Dễ Dàng Mở Rộng và Bảo Trì Mã
  3. 3. Những Lỗi Phổ Biến và Cách Khắc Phục
    1. 3.1. Thiếu Giá trị Mặc định
    2. 3.2. Phòng Tránh Vòng Lặp Vô Hạn
    3. 3.3. Lỗi Liên Quan đến Phạm vi Biến (Scope) và Execution Context
  4. 4. Các Tình Huống Ứng Dụng trong Dự Án Thực Tế
    1. 4.1. Tối Ưu Hàm Xử Lý API
    2. 4.2. Phòng tránh vòng lặp vô hạn