+1

Hiểu về Closures trong JavaScript: Hướng dẫn chi tiết

Closures là một trong những khái niệm mạnh mẽ nhưng đôi khi gây nhầm lẫn trong JavaScript. Đây là một chủ đề phổ biến trong các buổi phỏng vấn và đóng vai trò quan trọng trong việc viết code hiệu quả, có tính mô-đun và bảo mật cao.

Trong bài viết này, chúng ta sẽ cùng tìm hiểu về closures, cách chúng hoạt động, và các trường hợp sử dụng thực tế.

Closure là gì?

Closure là một hàm có thể ghi nhớ phạm vi (scope) bên ngoài của nó, ngay cả khi nó được gọi ngoài phạm vi đó.

VD:

function outerFunction(outerVariable) {
  return function innerFunction(innerVariable) {
    console.log(`Outer: ${outerVariable}, Inner: ${innerVariable}`);
  };
}

const newFunction = outerFunction("Hello");
newFunction("World");

Output khi này:

Outer: Hello, Inner: World

Giải thích:

  • outerFunction nhận một biến outerVariable.
  • innerFunction có thể truy cập biến của outerFunction, ngay cả khi nó được gọi bên ngoài phạm vi của outerFunction.

Cách Closures hoạt động

Closures hoạt động dựa trên lexical scoping (phạm vi từ vựng).

Khi một hàm được định nghĩa, nó sẽ ghi nhớ các biến trong phạm vi bên ngoài của nó.

Ngay cả khi hàm cha đã kết thúc, hàm con vẫn giữ một tham chiếu đến các biến của nó.

Tại sao điều này xảy ra?

JavaScript quản lý closures thông qua Execution Context (ngữ cảnh thực thi) và Scope Chain (chuỗi phạm vi).

  • Hàm con không chỉ có quyền truy cập vào biến cục bộ (local variables) của chính nó.
  • Nó còn có thể truy cập vào biến của hàm cha và biến toàn cục (global variables).

Ứng dụng thực tế của Closures

Closures không chỉ là một khái niệm lý thuyết mà còn rất hữu ích trong thực tế. Dưới đây là một số ứng dụng quan trọng của closures trong lập trình JavaScript.

1. Bảo mật dữ liệu (Data Privacy) - Encapsulation

Closures giúp tạo biến riêng tư, ngăn chặn truy cập trực tiếp từ bên ngoài.

function counter() {
  let count = 0;
  return {
    increment: function () { count++; console.log(count); },
    decrement: function () { count--; console.log(count); },
  };
}

const myCounter = counter();
myCounter.increment(); // 1
myCounter.increment(); // 2
myCounter.decrement(); // 1

Ở đây count là riêng tư và không thể truy cập trực tiếp.

2. Function Factories – Tạo hàm động dựa trên giá trị đầu vào

Closures giúp tạo ra các hàm có thể tùy chỉnh động, dựa trên giá trị đầu vào. Đây là cách tạo factory functions – một kỹ thuật phổ biến trong lập trình JavaScript.

function multiplier(factor) {
  return function (number) {
    return number * factor;
  };
}

const double = multiplier(2);
console.log(double(5)); // 10

Điều này hữu ích cho việc lập trình currying và lập trình chức năng .

3. Trình lắng nghe sự kiện với trạng thái

Closure giúp duy trì trạng thái trong trình xử lý sự kiện.

function attachEventListener() {
  let count = 0;
  document.getElementById("myButton").addEventListener("click", function () {
    count++;
    console.log(`Button clicked ${count} times`);
  });
}
attachEventListener();

Mỗi lần nhấp vào nút, trình lắng nghe sự kiện vẫn giữ quyền truy cập vào count.

4. Ghi nhớ (Tối ưu hóa hiệu suất)

Closure giúp lưu trữ kết quả và cải thiện hiệu suất.

function memoizedAdd() {
  let cache = {};
  return function (num) {
    if (num in cache) {
      console.log("Fetching from cache");
      return cache[num];
    } else {
      console.log("Calculating result");
      cache[num] = num + 10;
      return cache[num];
    }
  };
}

const add = memoizedAdd();
console.log(add(5)); // Calculating result → 15
console.log(add(5)); // Fetching from cache → 15

Các closure lưu trữ các giá trị đã tính toán trước đó, giúp giảm các phép tính trùng lặp.

Tóm tắt quan trọng về Closures

✅ Closures giúp các hàm ghi nhớ phạm vi bên ngoài của chúng, ngay cả khi hàm cha đã kết thúc. ✅ Closures được tạo tự động khi một hàm được trả về từ một hàm khác. ✅ Ứng dụng quan trọng của closures:

  • Bảo mật dữ liệu (Encapsulation) → Giữ biến riêng tư.
  • Function Factories → Tạo các hàm tùy chỉnh động.
  • Xử lý sự kiện (Event Handling) → Lưu trạng thái trong callback.
  • Tối ưu hiệu suất (Performance Optimization) → Memoization, caching.

💡 Closures có thể khó hiểu lúc đầu, nhưng khi nắm vững, chúng trở thành công cụ cực kỳ mạnh mẽ trong lập trình JavaScript. 🚀

Hy vọng bài viết này giúp ích cho các bạn!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí