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

Closure trong JavaScript: Gọi hàm bên ngoài và trả về hàm

Ví dụ gốc minh họa khái niệm Closure (bao đóng) — một hàm nội bộ ghi nhớ biến của hàm bên ngoài ngay sau khi hàm ngoài đã thực thi xong. Đây là nền tảng của function factory và private state trong JavaScript.

Code gốc (đã sửa lỗi chính tả)

// Hàm ngoài (outer function)
var subtractMethod = function () {
    var firstValue = 1000;
    var thirdValue = 200; // Biến này không được dùng trong ví dụ
    
    // Hàm trong (inner function) - tạo closure
    var divideMethod = function () {
        var secondValue = 500;
        console.log("Kết quả divideMethod() = " + (firstValue / secondValue));
        // Trả về phép trừ - dùng biến firstValue từ outer scope
        return (firstValue - secondValue);
    };
    
    // Trả về chính hàm divideMethod (chưa gọi)
    return divideMethod;
};

// Gọi subtractMethod() -> trả về hàm divideMethod
var result = subtractMethod(); // result giờ là hàm divideMethod

// Gọi hàm đã trả về
console.log("Kết quả subtractMethod() = " + result());

Chạy với Node.js

node ten_file.js

Kết quả

Kết quả divideMethod() = 2
Kết quả subtractMethod() = 500

Giải thích chi tiết

  1. subtractMethod() chạy, tạo biến cục bộ firstValue = 1000.
  2. Nó định nghĩa hàm divideMethod — hàm này có quyền truy cập firstValue (lexical scoping).
  3. subtractMethod trả về divideMethod (hàm), không gọi nó (không có dấu ngoặc).
  4. Biến result nhận hàm divideMethod.
  5. Khi gọi result():
    • divideMethod chạy, tạo secondValue = 500.
    • In ra 1000 / 500 = 2.
    • Trả về 1000 - 500 = 500.

Tại sao đây là Closure?

Hàm divideMethod "đóng gói" (close over) biến firstValue từ phạm vi bên ngoài. Ngay cả khi subtractMethod đã kết thúc, firstValue vẫn sống trong bộ nhớ vì divideMethod vẫn tham chiếu đến nó.

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

1. Function Factory (Tạo hàm cấu hình)

function createMultiplier(factor) {
    return function(number) {
        return number * factor;
    };
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5));  // 10
console.log(triple(5));  // 15

2. Private State (Trạng thái riêng tư)

function createCounter() {
    let count = 0; // Private - không truy cập trực tiếp từ ngoài
    return {
        increment: () => ++count,
        decrement: () => --count,
        getValue: () => count
    };
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
console.log(counter.getValue()); // 2
// count không thể truy cập: counter.count // undefined

3. Module Pattern

const MyModule = (function() {
    let privateVar = 'Bí mật';
    function privateMethod() { console.log(privateVar); }
    return {
        publicMethod: function() { privateMethod(); }
    };
})();
MyModule.publicMethod(); // "Bí mật"

Lưu ý quan trọng

  • Closure tạo ra khi hàm được định nghĩa, không phải khi gọi.
  • Mọi hàm trong JS đều là closure (vì đều có scope chain), nhưng thuật ngữ thường dùng cho hàm trả về/hàm callback giữ tham chiếu scope ngoài.
  • Cẩn thận rò rỉ bộ nhớ (memory leak) nếu closure giữ tham chiếu lớn không cần thiết.