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 ở trong hàm Closure
  • Biến được khai báo ở hàm cha chứa Closure (outer perform)
  • Biến toàn cục (world)

Hàm Closure ra sao?

Bên cạnh 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:

perform outerFuc() { var title = ‘Mai Truc Lam’; perform 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(perform cha)
  • Perform innerFunc, trong perform 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 perform functionOuter.

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

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

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

Xem Thêm  NPS là gì? Bí quyết tính NPS để đo lường sự hài lòng của khách hàng dành cho công ty

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 lúc 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 nằm trong 1 hàm khác, trường hợp hàm cha thực thi trước sẽ tạo ra 1 môi trường Lexical đặt hầu hết 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 lúc hàm innerFunc() “chết” theo biến mới đượ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 ở trong 1 hàm khác và có thể dùng biến title của hàm cha outerFuc(). Ví dụ 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 facility: 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 facility

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

perform makeExponentiation(x) { var exponent = x; return perform(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));

Trong đấy, bạn có thể thấy hàm makeExponentiation giống như 1 Perform manufacturing facility lúc có thể tạo ra được những Perform tùy 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).

Xem Thêm  High 6 sàn thanh toán Bitcoin uy tín trên thị trường crypto

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 fake lập/ mô phỏng/ hack bằng phương pháp dùng Closure. Bạn có thể xem code sau đây:

perform Counter() { var counter = 0; perform add(quantity) { counter += quantity; } return { increment: perform() { add(1); }, decrement: perform() { add(-1); }, worth: perform() { return counter; } }; }); var counter = Counter(); console.log(‘giá trị ban đầu’ + counter.worth()); counter.increment(); counter.increment(); console.log(‘sau lúc nâng cao lên 1’ + counter.worth()); counter.decrement(); console.log(‘sau lúc 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à “bí quyết” 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 ở 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ự có
  • Outer Capabilities 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ổ biến 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é!

// đây là world scope var e = 10; perform sum(a){ return perform(b){ return perform(c){ // outer features scope return perform(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; perform sum(a){ return perform sum2(b){ return perform sum3(c){ // outer features scope return perform sum4(d){ // native scope return a + b + c + d + e; } } } } var sum2 = sum(1); var sum3 = sum2(2); var sum4 = sum3(3); var outcome = sum4(4); console.log(outcome) //log 20

Xem Thêm  Phương pháp tiết kiệm Kakeibo là gì? Hướng dẫn chi tiết cách sử dụng phương pháp Kakeibo

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ể nói rằng: Closure có khả năng truy cập vào hầu hết phạm vi của Outer Perform.

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

Đây ko buộc phải 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 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.

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ể. Lý do là vì Closure sẽ có thể liên quan 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ật 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
  • Electronic mail: gross [email protected]
  • Web site: www.tino.org