Bài 4. Hàm

Hàm là trái tim của JavaScript. Bài này trình bày hàm thường, hàm mũi tên, tham số mặc định và callback.

35 phútCơ bản
Bạn sẽ học được
  • Viết hàm theo hai cách
  • Dùng hàm mũi tên (arrow function)
  • Dùng tham số mặc định, rest
  • Hiểu hàm có thể truyền như giá trị (callback)
Thuật ngữ cần biết
Hàm mũi tên
Cách viết gọn: (a, b) => a + b.
Callback
Hàm được truyền vào hàm khác để gọi sau.
Phạm vi (scope)
Biến khai báo bằng let/const chỉ sống trong khối chứa nó.
Closure
Hàm nhớ được biến ở nơi nó được tạo ra.

Khái niệm và lý thuyết

Trong JavaScript, hàm là giá trị hạng nhất: có thể gán cho biến, đưa vào mảng, truyền làm đối số và trả về từ hàm khác. Đây là nền tảng của lập trình hàm và của cơ chế sự kiện, xử lý bất đồng bộ.

Callback là hàm được đưa cho hàm khác để "gọi lại" khi có việc xong, ví dụ setTimeout(f, 1000). Closure xảy ra khi hàm bên trong nhớ các biến của hàm bên ngoài ngay cả sau khi hàm ngoài đã kết thúc; nhờ đó ta tạo được biến "riêng tư" và các bộ đếm như ví dụ dưới đây.

Hàm mũi tên (a, b) => a + b ngắn gọn và không có this riêng, nó dùng this của nơi định nghĩa, phù hợp cho callback. Hàm thường (function) có this riêng tùy cách gọi, hợp cho phương thức của đối tượng.

Khai báo hàm

function chao(ten = "bạn") {
  return `Xin chào ${ten}`;
}
console.log(chao("Lan"), chao());

const nhan = (a, b) => a * b;
const binhPhuong = x => x * x;
console.log(nhan(3, 4), binhPhuong(5));

Tham số còn lại và spread

function tong(...so) {
  return so.reduce((s, x) => s + x, 0);
}
console.log(tong(1, 2, 3, 4)); // 10
const a = [1, 2], b = [...a, 3, 4]; // [1,2,3,4]

Ví dụ: hàm tính giá sau khuyến mãi

function giaSauGiam(gia, phanTram = 10) {
  return gia * (1 - phanTram / 100);
}
const giam = gia => gia * 0.9;      // hàm mũi tên

console.log(giaSauGiam(200000));    // 180000
console.log(giam(200000));          // 180000

Hàm mũi tên viết gọn hơn và rất hay dùng làm đối số cho các hàm khác. Bạn có thể coi hàm là "một giá trị" như số hay chuỗi: truyền vào hàm khác, lưu vào biến, trả về từ hàm khác.

Callback

function lapLai(n, viec) {
  for (let i = 0; i < n; i++) viec(i);
}
lapLai(3, i => console.log("Việc số", i));

setTimeout(() => console.log("Sau 1 giây"), 1000);

Closure

function boDem() {
  let dem = 0;
  return () => ++dem;
}
const d = boDem();
console.log(d(), d(), d()); // 1 2 3
Tình huống: Bộ lọc giá

Cửa hàng muốn lọc sản phẩm theo điều kiện thay đổi (dưới 200k, dưới 500k...). Hàm nhận điều kiện làm tham số giúp dùng lại:

const loc = (ds, dk) => ds.filter(dk);
console.log(loc([120, 340, 90], g => g < 200)); // [120, 90]
Mẹo hay

Hàm một dòng ngắn dùng mũi tên; hàm dài, cần tên rõ ràng, dùng function.

Lưu ý

Hàm mũi tên không có this riêng; trong phương thức đối tượng cần cân nhắc.

Thực hành
  1. Viết hàm đảo ngược chuỗi.
  2. Viết hàm demNguyenAm(chuoi).
  3. Dùng setInterval in thời gian mỗi giây, dừng sau 5 lần.
Tóm tắt bài học
  • Hàm có thể là giá trị: gán biến, truyền, trả về.
  • Mũi tên viết gọn, tham số mặc định tiện lợi.
  • Callback và closure là nền tảng của lập trình bất đồng bộ.