Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Định nghĩa Function bên trong Function Body trong JavaScript (Closures)


Để đạt được mục đích này, dùng JavaScript Closures. Closure là function sử dụng scope nơi nó được khai báo khi được gọi, không phải scope nơi nó được gọi.

Ví dụ

Function innerDisplay là một closure:

var myFunction = (function () {
  function display() {
    // logic level 1
  }
  
  function innerDisplay(a) {
    if (/* some condition */) {
      // logic 1, 2
      display();
    } else {
      // logic 3, 4
      display();
    }
  }
  
  return innerDisplay; // Trả về inner function - tạo closure
})();

// Usage
myFunction(/* args */);

Closure - Giải thích sâu

Khi innerDisplay được trả về và gán cho myFunction, nó giữ tham chiếu đến scope của IIFE (Immediately Invoked Function Expression) nơi nó sinh ra. Biến display và các biến khác trong scope đó được "đóng gói" (closed over) - do đó gọi là closure.

Ví dụ thực tế: Private State / Module Pattern

const createCounter = () => {
  let count = 0; // Private variable (chỉ closure truy cập được)
  
  return {
    increment: () => ++count,
    decrement: () => --count,
    getCount: () => count
  };
};

const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
console.log(counter.getCount()); // 2
// count không truy cập trực tiếp từ bên ngoài

Ví dụ thực tế: Callback / Event Handler

function setupButton(buttonId, message) {
  const button = document.getElementById(buttonId);
  // Handler function tạo closure bao gồm `message`
  button.addEventListener('click', function() {
    alert(message); // Truy cập `message` từ outer scope
  });
}

setupButton('btn1', 'Hello from Button 1');
setupButton('btn2', 'Hello from Button 2');

Lưu ý

  • Closure tạo ra memory retention - biến trong closure không bị GC miễn closure còn sống. Cẩn thận memory leak.
  • Loop + closure classic bug (var trong for loop):
// ❌ Sai với var
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100); // In ra 3, 3, 3
}

// ✅ Đúng với let (block scoped) hoặc IIFE
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100); // 0, 1, 2
}