Discuss About Closures in JavaScript.

Nội dung bài viết

Closures là một trong những khái niệm quan trọng nhất, và cũng bị hiểu lầm nhiều nhất trong programming patterns. Vì vậy trong bài viết này chúng ta sẽ lướt qua một vài ví dụ và sẽ hiểu sâu hơn về chúng.

Tham gia cùng chúng tôi:

Facebook: Cộng đồng lập trình javascript

Facebook Thảo luận về Javascript, ReactJS, VueJS, AngularJS Việt Nam


Bài trước chúng ta đang nói về "10 khái niệm mỗi developer javascript cần phải biết" (Những ai chưa đọc nên đọc qua để biết mình thiếu sót điểm nào) trong đó có một khái niệm là Closures trong javascript.

Sau khi bài viết được xuất bản thì câu hỏi phản hồi khá nhiều về "Closures" cho fan page. Chính vì lẽ đó, hôm nay trong bài viết này, chúng ta cần làm rõ khái niệm này. 

Closures là một khía cạnh quan trọng của JavaScript mà mọi developer nên biết và hiểu. Và các ví dụ dưới đây sẽ cho các devjs biết nó hoạt động như thế nào? 

Vòng đời của một function (The lifecycle of a function)

Đầu tiên đi vào một function đơn giản mà ai ai cũng biết

function getValue(){
  var a = 1
  var b = 2
  return a + b
}

var val = getValue()
console.log(val)
// Output: 3

Giải thích một tý cho nó oai chứ ai mà chả biết : var a và b chỉ active trong body getValue() mà thôi, không ai có thể truy cập được chúng ngoài function đó. Điều này có nghĩa là chỉ có getValue() mới trả về được var a và b. Vì function getValue đã closed :D 

Vì sao Closure lại liên quan đến ví dụ trên, vì nó liên quan đến khái niệm scope trong javascript. 

Definition #1:

Closure là một chức năng có quyền truy cập vào phạm vi cha, ngay cả sau khi scope đã đóng.

Định nghĩa trên có nghĩa là gì? 

Đầu tiên bạn phải hiểu về scope như đã nói ở trên? Scope chính là tuổi thọ của một biến trong javascript. Bạn có thể thấy trong đó một biến được định nghĩa đóng một vai trò lớn trong khoảng thời gian của biến đó và các hàm trong chương trình của bạn có quyền truy cập vào đó. 

Bây giờ chúng ta đi tiếp ví dụ : Những biến nào được tạo bên trong function được gọi là local scope. Một biến local chỉ có thể được truy cập trong function (scope) mà nó được định nghĩa. 

Ví dụ dưới đây cho chúng ta thấy một lỗi khi bạn cố truy cập vào một biên local.

function speak(){
  var words = 'hi'; 
  console.log(words);
}
speak(); // 'hi'
console.log(words); // Uncaught ReferenceError: words is not defined

biến words là local, nếu cố gắng truy cập ở ngoài function thì chúng ta sẽ nhận được một error. Ok, tương phản với local scope thì đó chính là global scope.

Ví dụ

var words = 'hi';
function speak(){ 
  console.log(words);
}
speak(); // 'hi' 
console.log(words); // 'hi'

Giờ đây các bạn có thể truy cập biến words bất cứ ở đây, thoải mái đê... Xong, đó là những gì mà bạn cần nắm để trước khi đi vào Closure Funciton Bây giờ chúng tâ đi vào ví dụ closure, nếu bạn nào đang dùng Google Chrome thì mở console ra chuẩn bị test nào 

Để mở console cho cool thì dùng lệnh sau nếu [WINDOWS]: Ctrl + Shift + J hoặc [MAC]: Cmd + Opt + J Copy rồi paste ví dụ này vào console

function speak() {
  return function logIt() {
    var words = 'hi';
    console.log(words);
  }
}

Chúng ta vừa tạo xong function speak() và nhiệm vụ của nó return về một function khác có tên là logIt(). Và kết thúc là logIt() sẽ print ra words. Khi bạn đã sao chép nó vào console, chúng tôi sẽ tạo một biến và gán nó cho chức năng speak như sau :

var sayHello = speak();

Bây giờ chúng ta có thể thấy giá trị của sayHello là gì bằng cách gọi biến nhưng không gọi hàm bên trong:

sayHello;
//  function logIt() {
//    var words = 'hi';
//    console.log(words);
//  }

Tại sao nó ko print ra 'hi'. Từ từ đừng nôn nóng nha. Nhưng nếu chúng ta có thể gọi

sayHello();
ouput: 
'hi'

Oà nó đã làm việc, nhưng điều đó là đương nhiên và không có gì đặc biệt. Bây giờ chúng ta move biến words ra ngoài function logIt(), thì nó sẽ như thế nào nha

function speak() {
  var words = 'hi';
  return function logIt() {
    console.log(words);
  }
}
var sayHello = speak();

tiếp tục gọi

sayHello

//  function logIt() {
//    console.log(words);
//  }

Ồ, không có biến words rồi :), giả sử gọi

sayHello()
output:
'hi'

Oạch, vô lý vậy? sao nó vần print ra 'hi', Cho dù biến words không được định nghĩa??? Tại sao vậy? haha bạn vừa trải qua những tác động của một closure! 

Hãy nhớ rằng Closure một chức năng có quyền truy cập vào phạm vi cha, ngay cả sau khi phạm vi đã đóng.

Giờ đây việc closure chạy như thế nào thì các bạn cũng đã hiểu hơn chưa? Nếu chưa thì hãy kiên nhẫn, chung ta ssẽ đi thêm một ví dụ nữa. ví dụ phức tạp hơn một chút

function name(n) {
  return function(a) {
    return `${n} likes ${a}`;
  };
}

Gọi lần lượt xem nó thế nào nha

var j = name('John');
var c = name('Cindy');

rồi outout ra xem nó return về gì?

j;

//  function (a) {
//    return `${n} likes ${a}`;
//  }

Chung ta hình dung ra rồi vì closure được giới thiệu ở ví dụ trước rồi đúng không? Function vẫn có thể truy cập biến n từ phạm vi cha. Tất cả những gì chúng ta cần làm là vượt qua giá trị của a khi gọi hàm. Thử tiếp xem :

j('dogs');  // 'John likes dogs'
c('cats');  // 'Cindy likes cats'

wow nó vẫn làm việc :D Closure cho phép bạn thực hiện các biến provate trong javascript. Chúng cũng giúp chức năng của javascript hay hơn, vì nếu không có chúng, sẽ không thể trả về các hàm cần truy cập vào các biến được xác định tại thời điểm hàm được khai báo.

#Kết Luận

Tham gia cùng chúng tôi:

Facebook: Cộng đồng lập trình javascript

Facebook Thảo luận về Javascript, ReactJS, VueJS, AngularJS Việt Nam

Hy vọng rằng bây giờ bạn có thể hiểu những điều cơ bản về Closure trong JavaScript và cách chúng hoạt động! Đây chỉ là phần nổi của tảng băng trôi. Bây giờ bạn có kiến thức để tìm hiểu về các ví dụ phức tạp và thực tế hơn về Closure. 

Cảm ơn các bạn đã đọc, nếu các bạn cảm thấy hiểu hơn xin hãy share ra cho mọi người cùng thảo luận. 

Mọi ý kiến và thắc mắc bạn của gửi về fan page. 

Tham khảo 

https://www.sohamkamani.com/blog/javascript/2018-10-31-how-do-javascript-closures-work/#some-more-examples

https://codeburst.io/understand-closures-in-javascript-d07852fa51e7

https://www.codingame.com/playgrounds/6516/closures-in-javascript-for-beginners