Closure

Function scope

Các biến được định nghĩa bên trong hàm không thể được truy cập từ ngoài hàm. Một hàm được định nghĩa bên trong một hàm khác có thể truy cập tất cả các biến được định nghĩa trong hàm cha của nó.

Ví dụ về hàm add() là hàm con của hàm getScore(). Hàm add() này có thể truy cập được các biến của hàm getScore().

1
2
3
4
5
6
7
8
9
function getScore() {
  var num1 = 2, num2 = 3;

  function add() {
    return 'Điểm số ' + (num1 + num2); // truy cập biến của hàm cha
  }
  return add();
}
getScore(); // "Điểm số 5"

Trùng tên biến trong hàm

Tên biến trong hàm được ưu tiên từ hàm con tới hàm cha, từ trong ra ngoài. Tính chất này được gọi là scope chain.

1
2
3
4
5
6
7
8
function outside() {
  var x = 5; // biến x ở hàm cha
  function inside(x) { // biến x là tham số
    return x * 2; // lấy biến x tham số
  }
  return inside(10);
}
outside(); // 20

Closure

Closure là một trong những tính năng mạnh mẽ nhất của JavaScript. Closure cũng chính là tính năng function scope.

  • Hàm cha lại không truy cập được các biến trong hàm con (tính chất bao đóng)
  • Hàm con được sử dụng các biến của hàm cha (các biến này được gọi là môi trường của hàm con)
  • Khi hàm cha thực thi xong thì các biến bên trong vẫn chưa được xóa đi. Chúng vẫn được lưu trữ cho hàm con sử dụng.

Closure có thể là tính năng của Javascript. Cũng một số tài liệu khác nói là closure là hàm mà lưu giữ lại các giá trị biến bên ngoài của hàm đó, ngay cả khi hàm bên ngoài đã thực thi xong.

Ví dụ sau tạo tên con vật với hàm setNamegetName. Lưu ý khi chạy xong hàm createPet(), biến name trong hàm này vẫn tồn tại.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
var createPet = function() {
  var name;
  return {
    setName: function(newName) {
      name = newName;
    },
    getName: function() {
      return name;
    }
  }
}

var pet = createPet();
pet.setName('Vivie');
pet.getName();                  // Vivie

pet.setName('Oliver');
pet.getName();                  // Oliver

Biến name không thể được truy cập bên ngoài, tuy nhiên chúng ta có thể viết các hàm để truy cập chúng. Đây gọi là tính bao đóng (encapsulation).

Ví dụ khác với hàm trả về api code:

1
2
3
4
5
6
7
8
9
var getCode = (function() {
  var apiCode = '0]Eal(eh&2';    // API code
  
  return function() {
    return apiCode;
  };
})(); // thực thi hàm ngay khi khai báo

getCode();    // 0]Eal(eh&2

Trong ví dụ trên chúng ta chỉ có thế nhận apiCode chứ không thể sửa apiCode ở bên ngoài hàm getCode được (tính chất bao đóng).