Mặc dù hầu hết các Lập trình viên Front end đã biết sử dụng tất cả các từ khóa var, let, const, nhưng nếu bạn chưa hiểu rõ thì đây là bài viết dành cho bạn.
Trong bài viết này, chúng ta sẽ thảo luận chi tiết về var, let và const liên quan như thế nào đến phạm vi (scope), cách sử dụng và vấn đề hosting của chúng.
Ở cuối bài viết, mình cũng sẽ cung cấp bảng so sánh trực quan để bạn hiểu nhanh về sự khác nhau giữa 3 từ khóa này.
1. Từ khóa var
Bất cứ khi nào một biến được khai báo bằng từ khóa var
, các biến đó là:
-
Phạm vi hàm (function scope) hoặc phạm vi toàn cục (global scope)
-
Có thể gán lại (Re-assignable) và có thể khai báo lại (Re-declarable)
-
Không thuộc vùng chết tạm thời (Temporal Dead Zone - TDZ)
1.1. Phạm vi của biến khí sử dụng var
Khi một biến được khai báo trong một hàm bằng cách sử dụng var
, thì biến đó sẽ nằm trong phạm vi của hàm.
Tuy nhiên, khi biến được khai báo trong một khối hoặc bên ngoài hàm thì biến toàn cục có phạm vi toàn cục.
Ngoài ra, nó cũng tạo một thuộc tính toàn cục trên đối tượng window
. (cùng tên window)
var language = "JavaScript";
function foo() {
var language = "Python";
framework = "React";
console.log(language);
}
foo(); // "Python"
console.log(language); // "JavaScript"
console.log(window.language); // "JavaScript"
console.log(window.framework); // "React"
Cũng cần lưu ý là các biến được khai báo mà không có bất kỳ câu lệnh nào sẽ trở thành một biến toàn cục theo mặc định.
Nếu bạn muốn tránh hành vi này thì bạn có thể sử dụng chế độ nghiêm ngặt trong JavaScript bằng cách thêm "use strict"
ở đầu tệp.
1.2. Gán lại biến và Khai báo lại biến sử dụng từ khóa var
Các biến được khai báo bằng var
có thể được gán lại và khai báo lại sau này trong chương trình JS.
var language = "JavaScript";
var language = "Python"; // Khai báo lại biến
console.log(language); // "Python"
language = "Java"; // Gán lại biến
console.log(language); // "Java"
Nói chung là sử dụng var thì bạn gán lại, khai báo lại thoải mái.
Nhưng có thể bạn sẽ không biết biến nào dùng ở chỗ nào (vì nó không còn duy nhất, giá trị đã có thể đã bị thay đổi ở đâu đó trong mớ hỗn độn kia)
> Vì JavaScript là ngôn ngữ kiểu Dynamic nên rất linh hoạt ở tên, kiểu dữ liệu. Ngược lại các ngôn ngữ kiểu Static như Java thì lại yêu cầu rất chặt chẽ ở phần này. Nếu bạn thích sự chặt chẽ, tham khảo ngay KHÓA HỌC JAVA (full stack), hợp tác với chuyên gia doanh nghiệp đào tạo - tuyển dụng.
1.3. Vấn đề hoisting khi sử dụng từ khóa var
Hoisting trong JavaScript là một cơ chế mà các biến và khai báo hàm (funcrion declaration) được chuyển lên đầu phạm vi của chúng trước khi thực thi code, thực sự gán giá trị.
Do đó các biến khai báo bằng từ khóa var
được đưa lên đầu phạm vi của chúng và được khởi tạo với giá trị undefined
.
// Có thể sử dụng biến ở trên
// Nhưng biến đó chưa được gán giá trị
// Nó giữ giá trị mặc định
console.log(myVar); // undefined
// Khai báo biến ở dưới
var myVar = "NIIT";
Hành vi của nó giống như thế này:
var myVar;
console.log(myVar); // undefined
// Gán giá trị cho biến
myVar = "NIIT";
Tương tự, ở trong một hàm:
function myFunc() {
console.log(myVar);
// Khai báo biến
var myVar = "NIIT";
}
// Thực thi hàm
myFunc(); // undefined
Khai báo cũng được kéo lên đầu phạm vi của nó.
function myFunc() {
// Khai báo biến
var myVar;
console.log(myVar);
// Gán giá trị
myVar = "NIIT";
}
// Thực thi hàm
myFunc(); // undefined
// Biến myVar có phạm vi hàm nên
// không thể truy cập biến myVar
console.log(myVar); // error...
Ở đây chúng ta cũng thấy thêm tác dụng của từ khóa var khiến cho myVar có phạm vi hàm.
Do đó, ta không thể truy cập nó ở bên ngoài hàm được.
2. Từ khóa let
Bất cứ khi nào một biến được khai báo bằng từ khóa let
, các biến đó là:
-
Phạm vi khối (Block scope)
-
Có thể gán lại nhưng không thể khai báo lại
-
Phụ thuộc vào vùng chết tạm thời (TDZ)
2.1. Phạm vi của biến khi sử dụng let
Khi được khai báo bên trong một khối { }
, biến sử dụng từ khóa let có phạm vi khối (Block scope) đó.
Tương tự như vậy, khi được khai báo bên trong hàm, biến có phạm vi hàm.
Tuy nhiên, không giống như var, nó không tạo thuộc tính toàn cục trên đối tượng window.
{
let language = "React"; // Phạm vi khối
console.log(language); // "React"
}
console.log(window.language); // undefined
console.log(language); // error
Cố gắng truy cập biến language bên ngoài khối sẽ bị lỗi.
function foo() {
let language = "Python";
console.log(language);
}
foo(); // Python
console.log(language); // error...
Bên trong hàm, nếu biến được khai báo bằng từ khóa let, nó cũng ngăn cản bạn truy cập trực tiếp ở ngoài hàm.
2.2. Biến sử dụng từ khóa let cho phép gán lại nhưng KHÔNG CÓ PHÉP khai báo lại
Không thể khai báo lại bất kỳ biến nào đã được khai báo với từ khóa let
. Nếu bạn làm như vậy, bạn sẽ nhận được một thông báo lỗi.
let language = "JavaScript";
let language = "Java"; // Lỗi Lỗi rồi
Nhưng bạn có thể gán lại biến.
let language = "JavaScript";
language = "Python";
console.log(language); // "Python"
2.3. Vấn đề hoisting khi sử dụng từ khóa let
Về cơ bản, bạn không thể sử dụng biến được khai báo bằng từ khóa let trước khai báo chúng.
console.log(language); // Lỗi
let language;
Lúc này, biến laguage đang nằm trong vùng chết tạm thời (TDZ)
TDZ ngăn truy cập vào các khai báo let trước khi khởi tạo chúng.
Do đó, khi một biến được truy cập mà không cần khai báo, thì lỗi ReferenceError sẽ được ném ra.
3. Từ khóa const
Bất cứ khi nào một biến được khai báo bằng từ khóa const, các biến đó là:
-
Không thể gán lại cũng không thể khai báo lại
-
Phụ thuộc vào vùng chết tạm thời
3.1. Phạm vi của biến sử dụng từ khóa const
const rất giống với let vì các biến được khai báo với const cũng có phạm vi khối.
const language = "JavaScript";
{
const language = "React"; // Phạm vi khối
console.log(language); // "React"
}
function foo() {
const language = "Python";
console.log(language);
}
foo(); // "Python"
console.log(language); // "JavaScript"
console.log(window.language); // undefined
3.2. Biến const không thể gán lại cũng như khai báo lại
Bất kỳ biến nào được khai báo với từ khóa const đều không thể được khai báo lại và cũng không thể được gán lại.
Nếu bạn làm như vậy, bạn sẽ nhận được thông báo lỗi ngay.
// Sử dụng từ khóa const
const brand = "NIIT";
// Khai báo lại biến const
const brand = "ICT"; // Lỗi
let brand = "ABC"; // Lỗi
var brand = "DEF" // Lỗi
// Gán lại giá trị cho biến const
brand = "BCD"; // Lỗi
Tuy nhiên, nên nhớ là biến được khai báo với từ khóa const có phạm vi khối.
Thế nên bạn vẫn có thể khai báo biến cùng tên ở ngoài phạm vi khối (Tuy nhiên, không khuyến khích bạn làm thế)
// Khai báo biến const bên ngoài hàm
const PI = "Số PI";
function myFunc() {
// Khai báo biến const trong hàm
const PI = "3.14";
console.log(PI)
}
myFunc(); // 3.14
console.log(PI); // Số PI
Và nên nhớ là, khi khai báo bất kỳ một biến const nào, bạn phải gán cho nó một giá trị.
const language; // Lỗi
language = "JavaScript";
3.3. Hành vi hoisting của biến const
Hành vi hoisting của biến const tương tự như hành vi của biến let.
console.log(language); // TDZ
const language = "JavaScript";
// ReferenceError: language is not defined
Bạn không thể truy cập biến khi chưa khai báo.
3.4. Biến const không thực sự CONST
Từ khóa const có thể hơi gây hiểu nhầm một chút.
Từ khóa const KHÔNG định nghĩa một giá trị không đổi. Nó xác định một tham chiếu không đổi đến một giá trị.
Do đó, chúng ta không thể thay đổi các giá trị nguyên thủy, nhưng chúng ta có thể thay đổi các thuộc tính của các đối tượng const.
Ví dụ, nếu chúng ta gán giá trị nguyên thủy cho một biến const thì chúng ta không thể thay đổi nó:
const PI = 3.14;
// Cố gắng thay đổi giá trị biến const
PI = 3; // Lỗi
PI = PI++; // Lỗi
Nhưng lại có thể thay đổi thuộc tính của đối tượng const:
// Tạo một đối tượng const
const school = {
name: "NIIT",
age: 18,
website: "niithanoi.edu.vn"
};
// Thay đổi thuộc tính
school.name = "NIIT - ICT Hà Nội";
console.log(school.name); // NIIT - ICT Hà Nội
// Thêm thuộc tính mới
school.email = "hello@niithanoi.edu.vn";
console.log(school.email); // hello@niithanoi.edu.vn
Tuy nhiên, bạn không thể gán lại đối tượng const
// Tạo một đối tượng const
const school = {
name: "NIIT",
age: 18,
website: "niithanoi.edu.vn"
};
// Cố gắng gán lại đối tượng const
school = { // Lỗi
name: "ABC",
age: 18
};
Tương tự đối với mảng.
Bạn có thể thay đổi phần tử trong mảng, thêm phần tử mới.
const course = ["JAVA", "PHP", "PYTHON", "JS"];
// Có thể thay đổi phần tử
course[3] = "JAVASCRIPT";
// Có thể thêm phần tử
course.push("TESTER");
// Có thể loại bỏ phần tử
course.pop();
Tuy nhiên, bạn cũng không thể gán lại mảng
const course = ["JAVA", "PHP", "PYTHON", "JS"];
// Cố gắng gán lại mảng
course = ["JAV", "P8P", "PY", "JS"]; // Lỗi
Túm lại var, let, const
Bảng so sánh var, let, const trong JavaScript
Từ phiên bản ES6 của JavaScript, chúng ta có thêm từ khóa let và const giúp giải quyết các vấn đề của từ khóa var.
Sử dụng chúng không những bạn sẽ thấy cuộc đời tươi sáng hơn mà còn được người đến sau cảm tạ. :D
Mặc dù đây là một bài viết tương đối ngắn, mình hi vọng bạn hiểu được sự khác nhau của var, let, const trong JavaScript.
> Đọc thêm: HỌC JAVASCRIPT CƠ BẢN
---
HỌC VIỆN ĐÀO TẠO CNTT NIIT - ICT HÀ NỘI
Học Lập trình chất lượng cao (Since 2002). Học làm Lập trình viên. Hành động ngay!
Đc: Tầng 3, 25T2, N05, Nguyễn Thị Thập, Cầu Giấy, Hà Nội
SĐT: 02435574074 - 0914939543
Email: hello@niithanoi.edu.vn
Fanpage: https://facebook.com/NIIT.ICT/
#niit #niithanoi #niiticthanoi #hoclaptrinh #khoahoclaptrinh #hoclaptrinhjava #hoclaptrinhphp #java #php #python