Tìm hiểu về Var, Let và Const trong Javascript

1. Lời mở đầu

  • Như chúng ta đã biết thì ES6 mang lại cho chúng ta rất nhiều tính năng giúp cho việc viết code được rõ ràng, gọn ghẽ và tối ưu.
  • Một trong số nhưng tính năng của của ES6 đó là bổ sung let và const cho việc khai báo biến, thay cho việc dùng var như trước đây.
  • Trong bài viết này chúng ta sẽ đi tìm hiểu về var, let, và const đồng thời cho thấy được những điểm khác nhau giữa chúng cũng như lý do dùng cái này mà không dùng cái kia.

2. Var

2.1 Scope

  • Scope ở đây là phạm vi biến được sử dụng. Trước khi có ES6, JavaScript chỉ có 2 kiểu scope là Global ScopeFunction Scope. Và một biến khai báo với var có thể có thể là global scope hoặc function scope
  • Một biến có phạm vi là Global khi được khai báo bên ngoài một function
1
2
3
4
5
6
7
var carName = "Volvo";

// code here can use carName

function myFunction() {
// code here can also use carName
}

Biến Global có thể được truy xuất từ bất kì đâu trong một chương trình Javascipt

  • Một biến có Function Scope khi được khai báo bên trong một Function
1
2
3
4
5
6
7
8
// code here can NOT use carName

function myFunction() {
var carName = "Volvo";
// code here CAN use carName
}

// code here can NOT use carNameỞ

Biến Local chỉ được truy cập ở bên trong function nơi nó được khai báo.

  • Ta xem xét ví dụ sau:
1
2
3
4
5
6
7
var greeter = "hey hi";

function newFunction() {
var hello = "hello";
}

console.log(hello); // error: hello is not defined

Ở đây, greeter là biến có phạm vi global vì nó tồn tại bên ngoài function trong khi hello có function scope. Ta sẽ không thể truy cập biến hello ở bên ngoài function.

2.2 Biến var có thể được khai báo lại và update lại

  • Chúng ta có thể làm khai báo lại biến var như thế này ngay cả trong cùng một scope mà không có lỗi
1
2
var greeter = "hey hi";
var greeter = "say Hello instead";
  • Update lại biến:
1
2
var greeter = "hey hi";
greeter = "say Hello instead";

2.3 Hoisting

  • Hoisting là một cơ chế mà sự khai báo biến hay function được đưa lên đầu của scope trước khi code khai báo đó được thực thi.
  • Ví dụ với code thế này:
1
2
console.log(greeter);
var greeter = "say hello";

Sẽ được biên dịch thành:

1
2
3
var greeter;
console.log(greeter); //greeter is undefined
greeter = "say hello";
  • Như vậy các biến var sẽ được hoist lên đầu phạm vi và được khởi tạo một giá trị undefined

2.3 Vấn đề với Var

  • Chúng ta sẽ xem xét đoạn code sau:
1
2
3
4
5
6
7
8
var greeter = "hey hi";
var times = 4;

if (times > 3) {
var greeter = "say Hello instead";
}

console.log(greeter); //"say Hello instead"
  • times > 3 nên biến greeter sẽ được định nghĩa lại là "say Hello instead". SẼ có vấn đề khi mà bạn không nhớ ra rằng biến greeter đã được định nghĩa trước đó. Và ở những đoạn code khác mà bạn có sử dụng biến greeter, có thể bạn sẽ ngạc nhiên với output được đưa ra. Và nếu như code của bạn lên đến hàng nghìn dòng code thì bạn sẽ không thể biết được mình đã thay đổi giá trị của biến greeter ở đoạn nào !!!

3. Let

  • Để giải quyết những yếu điểm của Var, ES6 mang đến cho chúng ta Let. Sau đây chúng ta hay cũng xem cách Let hoạt động như thế nào nhé.

3.1 Scope

  • Let có phạm vi block scope
  • Một block là đoạn code giới hạn trong cặp dấu {}. Một biến được khai báo với let trong một block thì sẽ chỉ được sử dụng trong phạm vi block đó.
  • Ví dụ
1
2
3
4
5
6
7
8
let greeting = "say Hi";
let times = 4;

if (times > 3) {
let hello = "say Hello instead";
console.log(hello); //"say Hello instead"
}
console.log(hello); // hello is not defined

Sử dụng biến hello bên ngoài {}sẽ gây ra lỗi.

3.2 Biến Let có thể được update lại nhưng không được khai báo lại.

  • Giống như var, một biến được khai báo với let có thể được update trong phạm vi của nó.
1
2
let greeting = "say Hi";
greeting = "say Hello instead";
  • Không giống như var, một biến khai báo với let không được khai báo lại trong phạm vi scope.
1
2
let greeting = "say Hi";
let greeting = "say Hello instead"; //error: Identifier 'greeting'
  • Nếu 2 biến giống nhau được khai báo trong 2 scope khác nhau, thì sẽ không có lỗi vì trường hợp này, 2 biến sẽ được đối xử như là 2 instance khác nhau.
1
2
3
4
5
6
let greeting = "say Hi";
if (true) {
let greeting = "say Hello instead";
console.log(greeting); //"say Hello instead"
}
console.log(greeting); //"say Hi"

3.3 Sử dụng let an toàn hơn var

  • Let là lựa chọn tuyệt vời hơn var. Khi dùng let chúng ta k cần phải đắn đo liệu chúng ta đã sử dụng tên biến này trước đây hay chưa.
  • Với let, biến có phạm vi block, và không thể khai báo nhiều hơn 1 lần trong cùng phạm vi, như vậy vấn đề mà ta thảo luận bên trên với var sẽ không xảy ra.

3.4 Hoisting

  • Cũng giống var, khai báo với let cũng được hoist lên đầu scope.
  • Tuy nhiên không giống như var, biến sẽ được khởi tạo giá trị undefined, biến khai báo với let sẽ k được khởi tạo, do đó bạn sẽ nhận về Lỗi.
1
2
3
4
5
6
7
function checkHoisting() {
console.log(foo); // ReferenceError
let foo = "Foo";
console.log(foo); // Foo
}

checkHoisting();

4. Const

  • Biến được khai báo với const sẽ giữ giá trị hằng số. Khai báo với const và khai báo với let có một số điểm tương đồng.

4.1 Scope

  • Giống như khai báo với let, khai báo với const sẽ chỉ được truy cập trong phạm vi là block nơi nó được khai báo.

4.2 Biến Const không thể được update hay khai báo lại.

  • Biến được khai báo với const sẽ có giá trị không thay đổi trong phạm vi block. Nó sẽ không được update hay khai báo lại
  • Cụ thể khi khai báo một cái biến với const, chúng ta không thể làm như này
1
2
const greeting = "say Hi";
greeting = "say Hello instead"; //error : Assignment to constant variable.

hay như này

1
2
const greeting = "say Hi";
const greeting = "say Hello instead"; //error : Identifier 'greeting' has already been declared
  • Khi khai báo biến const, đồng thời cũng phải khởi tạo giá trị ngay tại thời điểm khai báo.
  • Lưu ý: Một object được khai báo với const, object đó sẽ không thể được update tuy nhiên những thuộc tính của object này lại có thể được update lại
1
2
3
4
5
6
7
8
9
10
const greeting = {
message: "say Hi",
times: 4
};
const greeting = {
words: "Hello",
number: "five"
}; //error : Assignment to constant variable.

greeting.message = "say Hello instead"; // OK. No Error

4.3 Hoisting

  • Giống như let, khai báo const được hoist lên đầu nhưng không được khởi tạo giá trị.

5. Kết luận

  • Bên trên mình đã trình bày những đặc điểm khi khai báo biến với var, let, và const dựa trên 3 mục chính là Scope, Được Update hay khai báo lại hay không và Hoisting. Mình xin được đúc rút những đặc điểm khác nhau giữa 3 cái như sau:
    • Khai báo var có scope là globally hoặc function trong khi letconst có scope là block
    • Biến khai báo với var có thể được update và khai báo lại trong phạm vi scope. Biến khai báo với let có thể được update nhưng không được khai báo lại
    • 3 thằng đều được hoist lên đầu của scope, nhưng biến khai báo với var sẽ được khởi tạo giá trị là undefined còn biến khai báo với letconst sẽ không được khởi tạo giá trị.
    • varlet có thể được khai báo mà không cần khởi tạo giá trị trong khi const phải được khởi tạo giá trị ngay khi khai báo.
  • Tài liệu tham khảo: