Bạn nên hiểu là khi bạn code javascript thì bạn đã dùng Closure rồi, bạn định nghĩa 1 hàm thì tức là bạn đã gián tiếp tạo 1 Closure (thực tế thì Javascript Engine tạo Closure Scope mỗi khi một function được định nghĩa). Không phải chỉ khi viết inner function thì mới có Closure.
Định nghĩa: A closure is the combination of a function and its lexical scope. In JavaScript, closures are created every time a function is created, at function creation time.
Vận dụng vào thực tế ở đây chắc nên hiểu là, dùng hiểu biết của bản thân về Closure để tạo ra pattern hoặc chức năng gì đó, mà vì có Closure mới giải quyết được, hoặc nhờ có Closure mà việc đó dễ dàng hơn. Vậy nên hiểu Closure sinh ra để giải quyết vấn đề gì, tại sao Javascript Engine lại tạo Closure mỗi khi create function.
Chi tiết dài dòng:
Định nghĩa function ở ECMAScript: function là first-class. First-class function nghĩa là 1 function có thể được lưu trữ trong 1 biến, có thể truyền vào hàm khác (arguments), hoặc return trong 1 hàm khác.
Problem xảy ra khi truyền function qua lại (concept Funarg problem).
VD: downwards funarg problem
let x = 10;
function foo() {
console.log(x);
}
function bar(funArg) {
let x = 20;
funArg();
}
//pass foo to bar
bar(foo);
Ở trên truyền foo vào function bar, biến x ở trong foo là free variable (free variable là biến ko phải local và ko phải biến argument, biến chưa định nghĩa). Problem là không biết nên binding value ở đâu vô cho free variable, nên lấy biến x = 10 hay 20 => sinh ra Closure. Người ta ko bind với biến ở hàm bar, vì biến đấy có thể bị sửa sau này bởi hàm call, khó debug, khó maintain. Closure lấy biến ở environment tạo ra nó, environment tạo ra nó lại chứa định nghĩa của hàm, nó tạo thành 1 vòng tròn (Closure tiếng anh nghĩa là 1 vòng khép kín). Nhờ có closure, 1 hàm có khả năng ghi nhớ outer function’s scope.
VD2: upwards funarg problem
function foo() {
let x = 10;
// Closure, capturing environment of `foo`.
function bar() {
return x;
}
return bar;
}
let x = 20;
let bar = foo();
bar(); // 10
Vận dụng Closure vào các pattern (để ý mấy cái use case nào cần pass function qua lại và cần dùng inner function để capture biến/hàm ở outer thì thường là cách sử dụng Closure):
- 1 cái phổ biến là callback -> là truyền function vào một hàm khác
- tạo function có private scope -> vd tạo function A có inner function là B và C, thì B với C có thể access biến và hàm ở A, nhưng ngoài global thì không access được -> có thể tạo oop class bằng function & closure
- Function Factory: inner function sử dụng nhiều config khác nhau từ outer
- Counter:
function A() {
let state = 1;
return function B() {
state++;
console.log(state);
}
}
//2, 3, 4
- share data giữa nhiều inner function
…
Hope it help!