Tìm hiểu về Closure chúng ta thường xuyên dùng closures trong JavaScript, tuy nhiên các bạn đã thật sự hiểu được về nhiệm vụ cũng như là công dụng của Closure chưa? Qua bài viết dưới đây sẽ bổ sung thêm nhiều thông tin đến bạn đọc, cùng tìm đọc nhé.
Mục lục
Tìm hiểu về Closure
Closure là gì?
Closure là một hàm được viết lồng vào trong một 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ả khi đã đóng và dùng biến cục bộ của bản thân Closure.
Trong JavaScript, Closure là một tính chất cực kì mạnh. Không những JavaScript, Closure còn xuất hiện trong hầu như các loại phương ngữ lập trình khác.
Trong JavaScript, Closure có 3 phạm vi truy cập biến số không giống nhau bao gồm:
- Biến ở trong hàm Closure
- Biến được khai báo ở hàm cha chứa Closure (outer function)
- Biến toàn cục (global)
Xem thêm :Công nghệ mua bán nhà đất hiện đại tại Nhadatmoi.net
Hàm Closure ra sao?
Bên cạnh lý thuyết, con người sẽ đi tìm hiểu về chẳng hạn như để rõ hơn về Closure nhé!
Đầu tiên, ta sẽ xem xét chẳng hạn như về Lexical scoping như sau:
function outerFuc() var name = 'Mai Truc Lam'; function innerFunc() console.log(name); innerFunc(); outerFuc(); // Kết quả: Mai Truc Lam
Trong đó, ta có:
- Biến toàn cục: name
- Function functionOuter(function cha)
- Function innerFunc, trong function innerFunc không hề có biến toàn cục nào nhưng trong hàm đang dùng một biến name của function functionOuter.
Điều chỉnh code một chút, chúng ta sẽ có Closure như sau:
function outerFuc() var name = 'Mai Truc Lam'; function innerFunc() console.log(name); return innerFunc; var refInnerFunc = outerFuc(); refInnerFunc(); // Kết quả: Mai Truc Lam
So sánh hiệu năng giữa việc dùng closures và prototype
Chẳng hạn như trên minh hoạ cách sử dụng closures. Bây giờ mình sẽ viết lại nó theo bí quyết sử dụng prototype:
functionObjId()this.id =1;ObjId.prototype.getId =function()returnthis.id;;ObjId.prototype.setId =function(_id)this.id = _id;;var myObject =newObjId();console.log(myObject.getId());// => 1myObject.setId(10);console.log(myObject.getId());// => 10
Kết quả trả về vẫn giống y hệt như trên. Tuy vậy, cách nào sẽ chạy nhanh hơn? Closures hay Prototype?
Dựa theo hậu quả so sánh tại bài viết Performance of prototype vs closure code in JavaScript, mình tóm tắt lại như sau:
- Định nghĩa đối tượng: JavaScript closures nhanh hơn.
- Năng lực tiết kiệm bộ nhớ và khởi tạo đối tượng mới: Prototype nhanh hơn.
- Truy xuất hàm (getter, setter): Prototype nhanh hơn.
Ưng dụng của Closure trên thực tế là gì?
Trong thực tế, ta sẽ thấy Closure có khá nhiều áp dụng như:
- Hình thành một Function factory: một hàm tạo ra một hàm khác
- Mô phỏng lại các 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 chẳng hạn như về 3 ứng dụng trên nhé!
Function factory
Chúng ta sẽ có code như sau:
function makeExponentiation(x) var exponent = x; return function(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 hai của 9 là ' + sqrt(9));
Tìm hiểu về Closure trong đó, bạn có khả năng thấy hàm makeExponentiation giống như một Function factory khi có khả năng xây dựng được những Function tùy theo tham số truyền vào. 2 Closure: sqrt và sqr sở hữu body giống nhau tuy nhiên khác biến tương đương (ENV – Variable Equivalent).
Xem thêm :9 yếu tố chọn thuê văn phòng hợp với công ty IT – Saigon Office
Mô phỏng lại phạm vi của biến trong lập trình hướng đối tượng mục tiêu
Bên trong JavaScript chưa có khái niệm class đúng nghĩa như trong C++ hay những phương 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ề thực chất đây chính là một cách giả lập/ mô phỏng/ hack bằng việc sử dụng Closure. Bạn có thể xem code sau đây:
function Counter() var counter = 0; function add(number) counter += number; return increment: function() add(1); , decrement: function() add(-1); , value: function() return counter; ; ); var counter = Counter(); console.log('giá trị ban đầu’ + counter.value()); counter.increment(); counter.increment(); console.log('sau khi tăng lên 1' + counter.value()); counter.decrement(); console.log('sau khi giảm xuống 1 ' + counter.value());
Trong đó, các hàm increment, decrement và value đều là Closure có body không giống nhau nhưng chia sẻ cùng một Variable Equivalent.
Chia sẻ chung Variable Equivalent chính là “bí quyết” mô phỏng class trong JavaScript. Khi Closure update một biến, Việc này đổi này cũng có thể được ghi lại và xác nhận ở các Closure khác.
Closure Scope Chain
Kế tiếp, chúng ta sẽ giải thích tiếp về các ý trong đoạn đầu tiên đã nói về 3 phạm vi Closure có khả năng truy xuất bao gồm:
- Local Scope: phạm vị tự có
- Outer Functions Scope: phạm vi bên ngoài (phạm vi của hàm cha)
- Global Scope
Tìm hiểu về Closure khi lập trình, một trong các sai lầm rộng rãi là không phát hiện ra hoàn cảnh Outer Function là một hàm lồng, dẫn tới việc: phạm vi của Outer Function là phạm vi của Outer Function. Việc làm này dẫn tới một chuỗi những phạm vi hàm vô cùng hiệu quả.
Xem thêm: 7 kỹ năng công nghệ thông tin cần có mà bạn không nên bỏ lỡ
Qua bài viết trên, odoovietnam.com.vn đã chia sẻ tới các bạn về tìm hiểu về Closure cho người mới cần biết. Hy vọng bài đăng sẽ đem lại các nàng nhiều nội dung có ích. Cảm ơn các nàng đã theo dõi bài viết!
Mỹ Phượng – Tổng hợp & chỉnh sửa
Tham khảo (techmaster.vn, viblo.asia, …)