Closure là gì? Tìm hiểu về Closure trong JavaScript

Có lẽ bạn chưa biết rằng, có siêu nhiều người “rớt phỏng vấn xin việc” chỉ vì Closure đấy! Vậy, Closure là gì? Tại sao Closure lại xuất hiện nhiều trong những buổi phỏng vấn tới như vậy? Đừng lo, Tino Group sẽ giải đáp những câu hỏi này và giúp bạn hiểu thêm về Closure trong JavaScript thông qua 1 số thí dụ nhé!

Tìm hiểu về Closure

Closure là gì?

Closure là 1 hàm được viết lồng vào trong 1 hàm khác và Closure có thể dùng biến toàn cục, biến cục bộ của hàm (hàm cha) ngay cả lúc đã đóng và dùng biến cục bộ của bản thân Closure.

Trong JavaScript, Closure là 1 thuộc tính siêu mạnh. Ko chỉ JavaScript, Closure còn có mặt trong gần như những loại ngôn ngữ lập trình khác.

Trong JavaScript, Closure có 3 phạm vi truy cập biến số khác nhau bao gồm:

  • Biến trên trong hàm Closure
  • Biến được khai báo trên hàm cha chứa Closure (outer operate)
  • Biến toàn cục (world)

Hàm Closure ra sao?

Ngoại trừ lý thuyết, chúng ta sẽ đi tìm hiểu về thí dụ để rõ hơn về Closure nhé!

Trước tiên, ta sẽ xem xét thí dụ về Lexical scoping như sau:

operate outerFuc() { var title = ‘Mai Truc Lam’; operate innerFunc() { console.log(title); } innerFunc(); } outerFuc(); // Kết quả: Mai Truc Lam

Trong ấy, ta có:

  • Biến toàn cục: title
  • Perform functionOuter(operate cha)
  • Perform innerFunc, trong operate innerFunc ko có biến toàn cục nào nhưng trong hàm đang dùng 1 biến title của operate functionOuter.

Thay thế đổi code 1 tí, chúng ta sẽ có Closure như sau:

operate outerFuc() { var title = ‘Mai Truc Lam’; operate innerFunc() { console.log(title); } return innerFunc; } var refInnerFunc = outerFuc(); refInnerFunc(); // Kết quả: Mai Truc Lam

Xem Thêm  Prime 5 công cụ đánh giá visitors web site miễn chi phí chính xác nhất

Có vẻ, bạn cũng đã thấy sự khác biệt trên đây rồi đúng ko nào? Trong đoạn code thứ 2, chúng ta sẽ thấy:

Hàm refInnerFunc đang gáng và tham chiếu tới kết quả của hàm outerFuc(); refInnerFunc trỏ tới hàm innerFunc nhưng chưa thực thi.

Sau khoản thời gian hàm outerFuc() thực thi xong, biến toàn cục của hàm sẽ được giải phóng

Lúc hàm innerFunc() thực thi sẽ ra kết quả là Mai Truc Lam. Nhưng kết quà này là của hàm cha outerFuc(). Nhưng điều này nghe có vẻ vô lý về mắt lý thuyết đúng ko?

Nhưng trong JavaScript, lúc 1 hàm thuộc 1 hàm khác, ví dụ hàm cha thực thi trước sẽ tạo ra 1 môi trường Lexical đặt đa số những biến đang có vào và gắn cho hàm con (trong thí dụ là: refInnerFunc) để dùng.

Cũng có thể giải thích như sau: lúc hàm outerFuc() “chết” đi sẽ để lại “di chúc” cho hàm con refInnerFunc() là 1 biến title, sau thời điểm hàm innerFunc() “chết” theo biến new được giải phóng.

Trong thí dụ trên, chúng ta có thể thấy được hàm refInnerFunc() là Closure, vì hàm này đang trên trong 1 hàm khác và có thể dùng biến title của hàm cha outerFuc(). Trường hợp có cả biến cục bộ của bản thân refInnerFunc() và biến world, refInnerFunc() cúng có thể dùng được.

refInnerFunc() sẽ tham chiếu tới môi trường Lexical và hàm innerFunc().

Ứng dụng của Closure trong thực tế là gì?

Trong thực tế, ta sẽ thấy Closure có khá nhiều ứng dụng như:

  • Tạo thành 1 Perform manufacturing unit: 1 hàm tạo ra 1 hàm khác
  • Mô phỏng lại những phạm vi của biến trong lập trình hướng đối tượng.
  • Closure Scope Chain

Để hiểu hơn, chúng ta lại đi vào thí dụ về 3 ứng dụng trên nhé!

Perform manufacturing unit

Chúng ta sẽ có code như sau:

operate makeExponentiation(x) { var exponent = x; return operate(y) { return Math.pow(y, exponent); } } var sqr = makeExponentiation(2); var sqrt = makeExponentiation(0.5); console.log(‘3 squared is ‘ + sqr(3)); console.log(‘căn bậc 2 của 9 là ‘ + sqrt(9));

Xem Thêm  Commerce coin là gì? High 6 sàn commerce coin lớn nhất thế giới

Trong ấy, bạn có thể thấy hàm makeExponentiation giống như 1 Perform manufacturing unit lúc có thể tạo ra được những Perform tùy thuộc} vào tham số truyền vào. 2 Closure: sqrt sqr sở hữu physique giống nhau nhưng khác biến tương đương (ENV – Variable Equal).

Mô phỏng lại phạm vi của biến trong lập trình hướng đối tượng

Bên trong JavaScript chưa có khái niệm class đúng nghĩa như trong C++ hay những ngôn ngữ lập trình khác. Trong ES6, cuối cùng, khái niệm class trong JavaScript cũng có. Tuy nhiên, về bản chất đây là 1 phương pháp giả lập/ mô phỏng/ hack bằng bí quyết dùng Closure. Bạn có thể xem code sau đây:

operate Counter() { var counter = 0; operate add(quantity) { counter += quantity; } return { increment: operate() { add(1); }, decrement: operate() { add(-1); }, worth: operate() { return counter; } }; }); var counter = Counter(); console.log(‘giá trị ban đầu’ + counter.worth()); counter.increment(); counter.increment(); console.log(‘sau thời điểm nâng cao lên 1’ + counter.worth()); counter.decrement(); console.log(‘sau thời điểm giảm xuống 1 ‘ + counter.worth());

Trong ấy, những hàm increment, decrement worth đều là Closure có physique khác nhau nhưng chia sẻ cùng 1 Variable Equal.

Chia sẻ chung Variable Equal chính là “cách” mô phỏng class trong JavaScript. Lúc Closure replace 1 biến, việc này đổi này cũng sẽ được ghi nhận trên những Closure khác.

Closure Scope Chain

Tiếp theo, chúng ta sẽ giải thích tiếp về những ý trong phần mở đầu đã đề cập về 3 phạm vi Closure có thể truy cập bao gồm:

  • Native Scope: phạm vị tự động có
  • Outer Features Scope: phạm vi bên bên cạnh (phạm vi của hàm cha)
  • International Scope

Lúc lập trình, 1 trong những sai lầm phổ thông} là ko nhận ra trường hợp Outer Perform là 1 hàm lồng, dẫn tới việc: phạm vi của Outer Perform là phạm vi của Outer Perform. Điều này dẫn tới 1 chuỗi những phạm vi hàm siêu hiệu quả.

Để chứng minh cho điều này, hãy cùng Tino Group xem xét 1 thí dụ sau đây nhé!

Xem Thêm  Mô hình Ponzi là gì? Những điều nên biết về mô hình đa cấp này

// đây là world scope var e = 10; operate sum(a){ return operate(b){ return operate(c){ // outer features scope return operate(d){ // native scope return a + b + c + d + e; } } } } console.log(sum(1)(2)(3)(4)); // log 20 // Bạn cũng có thể viết mà ko cần những hàm ẩn danh: // world scope var e = 10; operate sum(a){ return operate sum2(b){ return operate sum3(c){ // outer features scope return operate sum4(d){ // native scope return a + b + c + d + e; } } } } var sum2 = sum(1); var sum3 = sum2(2); var sum4 = sum3(3); var consequence = sum4(4); console.log(consequence) //log 20

Trong thí dụ trên, bạn có thể thấy 1 loạt những hàm lồng nhau. Đa số những hàm này đều có thể truy cập vào phạm vi của những hàm bên bên cạnh. Sở hữu trường hợp này, chúng ta có thể bảo rằng: Closure có khả năng truy cập vào đa số phạm vi của Outer Perform.

Cân nhắc về hiệu suất

Đây ko cần là 1 chức năng của Closure trong thực tế mà là 1 nhắc nhở. Do phần này quá ngắn nên Tino Group xin phép gộp chung vào thí dụ thay thế vì tách riêng vì nhắc nhở này có liên quan mật thiết tới thí dụ trên trên.

Việc tạo quá nhiều hàm trong 1 hàm khác lúc Closure ko cần thiết để giải quyết 1 tác vụ cụ thể. Nguyên nhân là vì Closure sẽ có thể tác động tiêu cực tới hiệu suất của script cũng như cả tốc độ xử lý lẫn mức tiêu thụ bộ nhớ!

Vì vậy, bạn hãy cân nhắc thực kỹ nhé!

Tới đây, Tino Group hello vọng rằng bạn đã hiểu Closure là gì cũng như hiểu hơn về Closure trong JavaScript thông qua những thí dụ. Chúc bạn sẽ thành công trên con đường lập trình đầy gian nan và thử thách nhé!

Bài viết có tham khảo từ nhiều nguồn: Dev.lớn, Medium, JavaScript Tutorial, Mozilla Developer, TutorialsTeacher, TopDev,…

Những câu hỏi thường gặp về Closure

CÔNG TY CỔ PHẦN TẬP ĐOÀN TINO

  • Trụ sở chính: L17-11, Tầng 17, Tòa nhà Vincom Heart, Số 72 Lê Thánh Tôn, Phường Bến Nghé, Quận 1, Thành phố Hồ Chí MinhVăn phòng đại diện: 42 Trần Phú, Phường 4, Quận 5, Thành phố Hồ Chí Minh
  • Điện thoại: 0364 333 333Tổng đài miễn phí tổn: 1800 6734
  • E-mail: gross [email protected]
  • Web site: www.tino.org