4.1. Tên biến cục bộ trùng tên với biến toàn cục
Vấn đề tên biến là một vấn đề "TO LỚN" trong lập trình. Trong JavaScript thì vấn đề này càng to hơn nữa.
Vì khi lập trình, chúng ta sẽ phải đặt tên biến, tên hàm, tên .... rất nhiều.
> Trong Java thì bạn sẽ không gặp vấn đề này bởi vì tính chặt chẽ của nó. Tham khảo ngay KHÓA HỌC JAVA WEB (Full stack) nếu bạn yêu thích tính chặt chẽ của ngôn ngữ lập trình.
Do đó, chúng ta sẽ có khả năng viết một hàm mà trong đó có tên biến (biến cục bộ) trùng với biến của chương trình chính (biến toàn cục).
Ví dụ:
// Khai báo biến toàn cục
var tong = 12;
function tongHaiSo(a, b) {
// Khai báo biến cục bộ
var tong;
tong = a + b;
return tong;
}
var ketqua = tongHaiSo(5, 6);
console.log(ketqua); // Kết quả: 11
console.log(tong); // Kết quả: 12
Khi ta tạo một biến tong toàn cục tong
có giá trị là 12
Trong hàm tongHaiSo(a, b)
ta cố tình tạo một biến tong
và gán cho nó là a + b
.
Như vậy khi gọi tongHaiSo(5, 6)
thì biến tong
toàn cục sẽ bị không thay đổi giá trị.
Trong JavaScript việc trùng tên hoàn toàn không gây ra lỗi chương trình.
Nhưng nó gây ra sự nhầm lẫn.
Chương trình đơn giản còn dễ nhìn, chương trình phức tạp thì mỏi mắt tìm bug luôn.
4.2. Từ khóa let và var
Ở bài biến trong JavaScript mình đã nói cơ bản về hai từ khóa let và var này, mình sẽ nói cụ thể hơn nhé.
Cụ thể let cho phép tạo ra biến có phạm vi trong một khối { }
, còn var thì không.
Ví dụ:
// Tạo ra một biến toàn cục
var hoTen = "Ngô Trung";
function changeName() {
if (true) {
var hoTen = "Nguyễn Văn A";
}
console.log(hoTen);
}
changeName(); // Kết quả: Nguyễn Văn A
console.log(hoTen); // Kết quả: Ngô Trung
Trong ví dụ này, ở trong hàm changeName()
thì ta sử dụng một câu lệnh if
(Chủ yếu để tạo ra một khối code mà thôi).
Ta khai báo var hoTen = "Nguyễn Văn A";
trong câu lệnh if này.
Lúc này, câu lệnh console.log(hoTen);
nằm trong hàm changeName()
, nằm ngoài hàm if
lại có thể truy cập đến biến hoTen
.
Điều này có nghĩa là gì?
Có nghĩa là biến hoTen
này có phạm vi là phạm vi hàm.
OK.
Bây giờ mới khó đây này.
Giả sử hàm của bạn không đơn giản như vậy mà khá là phức tạp.
Nhỡ đâu đó bạn lại khai báo thêm một biến hoTen
trong hàm changeName()
nữa thì vấn đề gì sẽ xảy ra?
// Tạo ra một biến toàn cục
var hoTen = "Ngô Trung";
function changeName() {
if (true) {
var hoTen = "Nguyễn Văn A";
}
// Tạo một block code
{
var hoTen = "Nguyễn Văn B";
}
console.log(hoTen);
}
changeName(); // Kết quả: Nguyễn Văn B
console.log(hoTen); // Kết quả: Ngô Trung
Việc khai báo như vậy hoàn toàn không làm lỗi chương trình.
Nhưng lúc này, việc nhầm lẫn sẽ xảy ra.
Câu lệnh console.log(hoTen);
mà bạn viết ý định truy cập đến biến nào đây???
* Cả vấn đề hoisting nữa. (Nhưng bạn sẽ được tìm hiểu nó sau)
Do đó, trong phiên bản ES2015 thì JavaScript có thêm từ khóa let để giải quyết vấn đề này.
Ở ví dụ bên trên, chúng ta thay từ khóa var
bằng từ khóa let
// Tạo ra một biến toàn cục
var hoTen = "Ngô Trung";
function changeName() {
if (true) {
let hoTen = "Nguyễn Văn A";
}
console.log(hoTen);
}
changeName(); // Kết quả: Ngô Trung
console.log(hoTen); // Kết quả: Ngô Trung
Như bạn thấy, câu lệnh console.log(hoTen);
nằm trong cùng một hàm nhưng không thể truy cập đến.
Bởi vì từ khóa let đã giới hạn các biến mà nó khai báo ở trong phạm vi khối (block scope).
Có nghĩa là nó chỉ có thể truy cập trong phạm vi dấu ngoặc nhọn { }
mà nó được khai báo.
Chúng là làm thế này thì được:
// Tạo ra một biến toàn cục
var hoTen = "Ngô Trung";
function changeName() {
if (true) {
let hoTen = "Nguyễn Văn A";
console.log(hoTen);
}
}
changeName(); // Kết quả: Nguyễn Văn A
console.log(hoTen); // Kết quả: Ngô Trung
Còn khi ta khai báo biến bằng từ khóa let nhưng mà ở phạm vi toàn cục như thế này:
// Tạo ra một biến toàn cục
let hoTen = "Ngô Trung";
function changeName() {
if (true) {
let hoTen = "Nguyễn Văn A";
console.log(hoTen);
}
console.log(hoTen);
}
changeName();
Thì kết quả ta sẽ được:
Nguyễn Văn A
Ngô Trung
Ngoài một hàm bạn cũng không thể truy cập đến biến:
{
let hoTen = "Nguyễn Văn A";
console.log(hoTen);
}
console.log(hoTen); // Kết quả: Ngô Trung
Bạn sẽ nhạn được lỗi là:
error: Uncaught ReferenceError: hoTen is not defined
Và một điểm hay nữa của let là nó không cho phép khai báo hai biến cùng tên trong cùng một phạm vi.
Ví dụ như thế này:
// Tạo ra một khối mã
{
let hoTen = "Ngô Trung";
// Cố tình khai báo biến cùng tên
// trong cùng phạm vi
let hoTen = "NIIT";
}
Lúc đó, bạn sẽ nhận được thông báo lỗi ngay lập tức tương tự như thế này.
Indentifier 'hoTen' has already been declared (6:6)