Blogブログ

Scroll

Closure trong JavaScript

suffix_ngothikimthoa

Xin chào các bạn, lại là mình, T - team Web đây!!

Dạo gần đây mình mới đọc xong quyển Head First JavasScript, một quyển sách dành cho begginer, khá thú vị và dễ hiểu. Mình đã học được khá nhiều kiến thức tưởng chừng đã hiểu rõ nhưng thật ra là chưa từ quyển sách này. Trong đó, có kiến thức về Closure mà sau khi đọc được mình đúng kiểu rất là tâm đắc và muốn chia sẻ với các bạn ngay lập tức. Cùng đọc để xem nó thú vị ở chỗ nào nhé!

closure in js

Trước tiên, mời bạn đoán xem kết quả của đoạn code sau đây nhé!

Ví dụ:
var aVar = "GLOBAL"; 
function whereAreYou() { 
 var aVar = "LOCAL"; 
 function inner() { 
  return aVar; 
 } 
 return inner(); 
} 
var result = whereAreYou(); 
console.log(result); 

OK, kết quả đúng như bạn đoán, chính là "LOCAL".
Tiếp theo nhé!

var aVar = "GLOBAL"; 
function whereAreYou() { 
 var aVar = "LOCAL"; 
 function inner() { 
  return aVar; 
 } 
 return inner; 
} 
var innerFunction = whereAreYou(); 
var result = innerFunction(); 
console.log(result); 

Kết quả là LOCAL! Tại sao vậy nhỉ?
Có ai như mình chọn "GLOBAL" không??

Lý do là, closure của một function bao gồm function và environment (môi trường) mà function đó tham chiếu đến.

Environment sẽ chứa các biến không được định nghĩa trong thân của function (biến local), cũng không được định nghĩa với tư cách là một biến global (mà biến đó được định nghĩa bên trong function chứa function đang nhắc tới, kể cả function ông nội, ông cố, bla bla... (trường hợp phía trên là function whereAreYou). Các biến này còn được gọi với tên là free variables.

Do đó, khi biến tham chiếu đến function inner được trả về, nó sẽ trả về cả function và environment mà function đó tham chiếu tới, ở đây, environment chứa biến aVar có giá trị là LOCAL.

Có thể bạn sẽ tự hỏi, mục đích của cái đám này là gì vậy (giống mình), thì sau đây sẽ là một vài ứng dụng hết sức đơn giản của closure.

Ví dụ không sử dụng closure:

var count = 0; 
function counter() { 
 count = count + 1; 
 return count; 
} 
console.log(counter()); 
console.log(counter()); 
console.log(counter()); 

Có lẽ bạn cảm thấy hài lòng với đoạn code này rồi, tuy nhiên, việc sử dụng count làm biến global khi làm việc trong một team có thể sẽ dẫn đến một số vấn đề, ví dụ như đặt trùng tên dẫn đến xung đột code...

Thử xem đoạn code này khi sử dụng closure nhé:

 function makeCounter() { 
 var count = 0; 
 function counter() { 
  count = count + 1; 
  return count; 
 } 
 return counter; 
} 
var doCount = makeCounter(); 
console.log(doCount()); 
console.log(doCount()); 
console.log(doCount()); 

Kỳ diệu không nào?


Thông tin bổ sung

Closure chứa một môi trường thật sự, không phải một bản copy.

Do đó, nếu một giá trị bị thay đổi bởi code bên ngoài closure function thì giá trị bên trong cũng sẽ thay đổi theo.

Ví dụ:

function bake(text) { 
 setTimeout(function() { 
  console.log(text); 
 }, 1000); 
 text = "failed"; 
} 
bake("done"); 

Khi chúng ta gọi setTimeout và truyền cho nó function, khi đó, một closure bao gồm function và tham chiếu đến môi trường của nó được tạo ra.
Sau đó, chúng ta thay đổi giá trị của text ở bên ngoài closure, dẫn đến giá trị được lưu bên trong môi trường cũng thay đổi theo.
Sau 1000 mili giây, function được gọi, lúc này, text đã mang giá trị là "failed". Do đó, kết quả được in ra màn hình là "failed".

Thú vị không nào?

Mình hi vọng bài blog hôm nay của mình đã mang đến cho các bạn thêm một kiến thức mới, cũng như một chút thú vị trong quá trình trau dồi, học hỏi của bản thân giống như mình nhé. Hẹn gặp lại các bạn vào kỳ tiếp theo nha!

Tham khảo: Head First JavaScript Programming

  1. TOP
  2. お知らせ
  3. ブログ
  4. Closure trong JavaScript

PAGE TOP