Biến là một cấu trúc dữ liệu chỉ định tên đại diện cho một giá trị. Chúng có thể chứa bất kỳ loại dữ liệu nào.
Tên của biến được gọi là mã nhận dạng. Giá trị nhận dạng hợp lệ phải tuân theo các quy tắc sau:
- Giá trị nhận dạng có thể chứa chữ cái Unicode, ký hiệu đô la ($), dấu gạch dưới ký tự (_), chữ số (0-9) và thậm chí một số ký tự Unicode.
- Giá trị nhận dạng không được chứa khoảng trắng vì trình phân tích cú pháp sử dụng khoảng trắng để
các phần tử đầu vào riêng biệt. Ví dụ: nếu bạn cố gọi một biến
my Variable
thay vìmyVariable
, trình phân tích cú pháp sẽ thấy hai giá trị nhận dạng,my
vàVariable
đồng thời gửi lỗi cú pháp ("mã thông báo không mong muốn: "). Giá trị nhận dạng phải bắt đầu bằng một chữ cái, dấu gạch dưới (
_
) hoặc ký hiệu đô la ($
). Chúng không được bắt đầu bằng chữ số để tránh nhầm lẫn giữa số và giá trị nhận dạng:let 1a = true; > Uncaught SyntaxError: Invalid or unexpected token
Nếu JavaScript cho phép các số ở đầu giá trị nhận dạng, thì điều đó sẽ cho phép giá trị nhận dạng chỉ bao gồm các số, gây ra xung đột giữa các số được dùng làm số và số được dùng làm giá trị nhận dạng:
let 10 = 20 10 + 5 > ?
"Từ dành riêng" mà đã có cú pháp có ý nghĩa không thể dùng làm giá trị nhận dạng.
Giá trị nhận dạng không được chứa ký tự đặc biệt (
! . , / \ + - * =
).
Dưới đây không phải là các quy tắc nghiêm ngặt để tạo giá trị nhận dạng, nhưng các phương pháp hay nhất trong ngành giúp duy trì mã dễ dàng hơn. Nếu dự án có các tiêu chuẩn khác nhau, hãy áp dụng các tiêu chuẩn đó để đảm bảo tính nhất quán.
Theo ví dụ do các phương thức và thuộc tính tích hợp của JavaScript đặt ra, viết hoa Camel (còn được cách điệu là "camelCase") là một quy ước rất phổ biến đối với giá trị nhận dạng được tạo thành từ nhiều từ. Nguyên tắc lạc đà là phương pháp viết hoa chữ cái đầu tiên của mỗi từ, ngoại trừ chữ cái đầu tiên của từ được cải thiện dễ đọc mà không có dấu cách.
let camelCasedIdentifier = true;
Một số dự án sử dụng các quy ước đặt tên khác tuỳ thuộc vào bối cảnh và tính chất của dữ liệu. Ví dụ: chữ cái đầu tiên của một lớp thường được viết hoa, vì vậy tên lớp có nhiều từ thường sử dụng một biến thể của camel viết hoa thường được gọi là "viết hoa kiểu lạc đà trên" hoặc Kiểu viết hoa Pascal.
class MyClass {
}
Giá trị nhận dạng phải mô tả ngắn gọn bản chất của dữ liệu có trong giá trị nhận dạng (đối với
ví dụ: currentMonthDays
là tên hay hơn theNumberOfDaysInTheCurrentMonth
)
và đọc nhanh và rõ ràng (originalValue
tốt hơn val
). Chiến lược phát hành đĩa đơn
Giá trị nhận dạng myVariable
dùng trong mô-đun này hoạt động trong bối cảnh
các ví dụ riêng biệt, nhưng sẽ rất không hữu ích trong mã sản xuất vì chúng
không cung cấp thông tin về dữ liệu chứa trong đó.
Giá trị nhận dạng không nên quá cụ thể về dữ liệu có trong giá trị nhận dạng, vì
giá trị của chúng có thể thay đổi tùy thuộc vào cách tập lệnh hoạt động dựa trên dữ liệu đó hoặc
quyết định mà những người duy trì trong tương lai đưa ra. Ví dụ: ban đầu biến đã cho
có thể cần thay đổi mã nhận dạng miles
thành một giá trị tính bằng km trong tương lai
dự án, yêu cầu nhà bảo trì thay đổi bất kỳ tham chiếu nào đến biến đó thành
để tránh nhầm lẫn trong tương lai. Để ngăn chặn điều này, hãy sử dụng distance
làm giá trị nhận dạng của bạn
thay thế.
JavaScript không cấp đặc quyền hoặc ý nghĩa đặc biệt nào cho các giá trị nhận dạng
bắt đầu bằng các ký tự dấu gạch dưới (_
), nhưng các ký tự này thường được sử dụng để cho biết rằng
biến, phương thức hoặc thuộc tính là "riêng tư" có nghĩa là mục đích
để sử dụng trong ngữ cảnh của đối tượng chứa đối tượng đó, và không nên
được truy cập hoặc sửa đổi bên ngoài ngữ cảnh đó. Đây là một quy ước được chuyển sang
từ các ngôn ngữ lập trình khác và có trước việc bổ sung đoạn mã
tài sản riêng tư.
Khai báo biến
Có nhiều cách để JavaScript nhận biết giá trị nhận dạng, một quy trình
có tên là "khai báo" một biến. Một biến được khai báo bằng let
, const
,
hoặc var
từ khoá.
let myVariable;
Sử dụng let
hoặc var
để khai báo một biến có thể thay đổi bất cứ lúc nào. Các
các từ khoá cho trình thông dịch JavaScript biết rằng một chuỗi ký tự là
mã nhận dạng có thể chứa giá trị.
Khi làm việc trong một cơ sở mã hiện đại, hãy sử dụng let
thay vì var
. var
vẫn hoạt động
trong các trình duyệt hiện đại, nhưng có một số hành vi không trực quan được xác định trong
các phiên bản JavaScript đầu tiên và sau đó không thể thay đổi thành
duy trì khả năng tương thích ngược. let
đã được thêm vào ES6 để giải quyết một số vấn đề
với thiết kế var
.
Một biến đã khai báo được khởi tạo bằng cách gán một giá trị cho biến đó. Sử dụng
dấu bằng đơn (=
) để gán hoặc gán lại một giá trị cho một biến. Bạn có thể
điều này dưới dạng một phần của cùng một tuyên bố khai báo điều đó:
let myVariable = 5;
myVariable + myVariable
> 10
Bạn cũng có thể khai báo một biến bằng let
(hoặc var
) mà không cần khởi tạo biến đó
ngay lập tức. Nếu bạn làm như vậy, giá trị ban đầu của biến này sẽ là undefined
cho đến khi
mã sẽ chỉ định một giá trị cho đoạn mã đó.
let myVariable;
myVariable;
> undefined
myVariable = 5;
myVariable + myVariable
> 10
Biến có giá trị undefined
khác với biến không xác định
có giá trị nhận dạng chưa được khai báo. Tham chiếu đến một biến mà bạn chưa có
khai báo sẽ gây ra lỗi.
myVariable
> Uncaught ReferenceError: myVariable is not defined
let myVariable;
myVariable
> undefined
Mối liên kết giữa một mã nhận dạng với một giá trị thường được gọi là "liên kết".
Cú pháp tuân theo các từ khoá let
, var
hoặc const
được gọi là
"danh sách liên kết" và cho phép khai báo nhiều biến được phân tách bằng dấu phẩy
(kết thúc bằng dấu chấm phẩy dự kiến). Thao tác này sẽ tạo các đoạn mã sau
giống hệt nhau về chức năng:
let firstVariable,
secondVariable,
thirdVariable;
let firstVariable;
let secondVariable;
let thirdVariable;
Việc chỉ định lại giá trị của một biến không sử dụng let
(hoặc var
) vì JavaScript
đã biết biến tồn tại:
let myVariable = true;
myVariable
> true
myVariable = false;
myVariable
> false
Bạn có thể chỉ định lại biến giá trị mới dựa trên giá trị hiện có của biến:
let myVariable = 10;
myVariable
> 10
myVariable = myVariable * myVariable;
myVariable
> 100
Nếu bạn cố gắng khai báo lại một biến bằng let
trong môi trường phát hành chính thức,
bạn sẽ gặp lỗi cú pháp:
let myVariable = true;
let myVariable = false;
> Uncaught SyntaxError: redeclaration of let myVariable
Trình duyệt công cụ cho nhà phát triển
thoải mái hơn trong việc khai báo lại let
(và class
), nên bạn có thể không
gặp lỗi tương tự trong bảng điều khiển dành cho nhà phát triển.
Để duy trì khả năng tương thích với trình duyệt cũ, var
cho phép khai báo lại một cách không cần thiết
không có lỗi trong bất kỳ ngữ cảnh nào:
var myVariable = true;
var myVariable = false;
myVariable\
> false
const
Dùng từ khoá const
để khai báo hằng số (một loại biến bắt buộc phải là)
được khởi tạo ngay lập tức và sau đó không thay đổi được. Giá trị nhận dạng cho hằng số
tuân theo tất cả các quy tắc tương tự như các biến được khai báo bằng let
(và var
):
const myConstant = true;
myConstant
> true
Bạn không thể khai báo một hằng số mà không chỉ định ngay một giá trị cho hằng số đó vì
hằng số sẽ không được chỉ định lại sau khi tạo, vì vậy, mọi hằng số chưa khởi tạo
hằng số sẽ ở undefined
vĩnh viễn. Nếu bạn cố gắng khai báo một hằng số
mà không khởi chạy thuộc tính này, bạn sẽ gặp lỗi cú pháp:
const myConstant;
Uncaught SyntaxError: missing = in const declaration
Việc cố gắng thay đổi giá trị của một biến được khai báo bằng const
theo cách mà bạn có thể
thay đổi giá trị của một biến được khai báo bằng let
(hoặc var
) dẫn đến một loại
lỗi:
const myConstant = true;
myConstant = false;
> Uncaught TypeError: invalid assignment to const 'myConstant'
Tuy nhiên, khi một hằng số được liên kết với một đối tượng, các thuộc tính của đối tượng đó có thể thay đổi đối tượng.
const constantObject = { "firstvalue" : true };
constantObject
> Object { firstvalue: true }
constantObject.secondvalue = false;
constantObject
> Object { firstvalue: true, secondvalue: false }
Hằng số chứa một đối tượng là một hằng số không thể thay đổi tham chiếu đến giá trị dữ liệu có thể thay đổi. Mặc dù hằng số đó không thể thay đổi nhưng các thuộc tính của tham số đó sẽ không thể thay đổi có thể thay đổi, thêm vào hoặc xoá đối tượng:
const constantObject = { "firstvalue" : true };
constantObject = false
> Uncaught TypeError: invalid assignment to const 'constantObject'
Khi bạn không muốn một biến được chỉ định lại, tốt nhất là bạn nên đặt biến đó
hằng số. Việc sử dụng const
giúp nhóm phát triển hoặc những người bảo trì trong tương lai biết về
dự án không thay đổi giá trị đó để tránh phá vỡ các giả định trong mã của bạn
về cách sử dụng biến đó, ví dụ: một biến cuối cùng sẽ được
được đánh giá dựa trên loại dữ liệu dự kiến.
Phạm vi biến
Phạm vi của biến là một phần của tập lệnh mà biến đó khả dụng.
Biến ngoài phạm vi của biến sẽ không được xác định, chứ không phải dưới dạng giá trị nhận dạng
chứa giá trị undefined
, nhưng như thể giá trị này chưa được khai báo.
Tuỳ thuộc vào từ khoá mà bạn dùng để khai báo một biến và ngữ cảnh mà theo đó bạn xác định nó, bạn có thể xác định phạm vi biến để chặn câu lệnh (phạm vi khối), hàm riêng lẻ (phạm vi hàm) hoặc toàn bộ ứng dụng JavaScript (phạm vi toàn cầu).
Phạm vi chặn
Mọi biến mà bạn khai báo bằng let
hoặc const
đều nằm trong phạm vi gần nhất
chứa câu lệnh khối,
có nghĩa là chỉ có thể truy cập biến trong khối đó. Đang cố gắng
việc truy cập vào một biến trong phạm vi khối bên ngoài khối chứa nó gây ra cùng một
lỗi khi cố truy cập một biến không tồn tại:
{
let scopedVariable = true;
console.log( scopedVariable );
}
> true
scopedVariable
> ReferenceError: scopedVariable is not defined
Có liên quan đến JavaScript, biến trong phạm vi khối không tồn tại bên ngoài khối chứa yếu tố đó. Ví dụ: bạn có thể khai báo một hằng số bên trong một khối rồi khai báo một hằng số khác bên ngoài khối đó sử dụng có cùng giá trị nhận dạng:
{
const myConstant = false;
}
const myConstant = true;
scopedConstant;
> true
Mặc dù một biến đã khai báo không thể mở rộng vào khối mẹ, nhưng biến đó là có sẵn cho tất cả các khối con:
{
let scopedVariable = true;
{
console.log( scopedVariable );
}
}
> true
Bạn có thể thay đổi giá trị của biến đã khai báo ngay từ bên trong khối con:
{
let scopedVariable = false;
{
scopedVariable = true;
}
console.log( scopedVariable );
}
> true
Một biến mới có thể được khởi tạo bằng let
hoặc const
bên trong một thành phần con
mà không có lỗi, ngay cả khi khối đó sử dụng cùng một giá trị nhận dạng với một biến trong
khối mẹ:
{
let scopedVariable = false;
{
let scopedVariable = true;
}
console.log( scopedVariable );
}
> false
Phạm vi hàm
Các biến được khai báo bằng var
đều nằm trong phạm vi hàm chứa gần nhất
(hoặc khối khởi động tĩnh bên trong một lớp).
function myFunction() {
var scopedVariable = true;
return scopedVariable;
}
scopedVariable;
> ReferenceError: scopedVariable is not defined
Trường hợp này vẫn xảy ra sau khi một hàm được gọi. Mặc dù được khởi tạo trong khi hàm thực thi, nên biến đó vẫn được không hoạt động bên ngoài phạm vi hàm:
function myFunction() {
var scopedVariable = true;
return scopedVariable;
}
scopedVariable;
> ReferenceError: scopedVariable is not defined
myFunction();
> true
scopedVariable;
> ReferenceError: scopedVariable is not defined
Phạm vi toàn cầu
Biến toàn cục có sẵn trong toàn bộ ứng dụng JavaScript, bên trong bất kỳ và tất cả khối và hàm, vào bất kỳ tập lệnh nào trên trang.
Mặc dù đây có vẻ như là một giá trị mặc định mong muốn, nhưng bất kỳ phần nào của ứng dụng có thể truy cập và sửa đổi có thể làm tăng chi phí không cần thiết hoặc thậm chí khiến xung đột với các biến ở nơi khác trong ứng dụng có cùng giá trị nhận dạng. Điều này áp dụng cho bất kỳ và tất cả JavaScript liên quan đến việc hiển thị một trang, bao gồm những thứ như thư viện của bên thứ ba và số liệu phân tích người dùng. Do đó, để tránh làm ô nhiễm phạm vi toàn cục bất cứ khi nào có thể.
Bất kỳ biến nào được khai báo bằng var
bên ngoài hàm mẹ hoặc bằng let
hay
const
bên ngoài khối mẹ, là toàn cục:
var functionGlobal = true; // Global
let blockGlobal = true; // Global
{
console.log( blockGlobal );
console.log( functionGlobal );
}
> true
> true
(function() {
console.log( blockGlobal );
console.log( functionGlobal );
}());
> true
> true
Gán một giá trị cho biến mà không khai báo rõ ràng (nghĩa là chỉ định
không bao giờ sử dụng var
, let
hoặc const
để tạo) sẽ nâng một biến lên
toàn cầu, ngay cả khi được khởi tạo bên trong một hàm hoặc khối. Biến
được tạo bằng mẫu này đôi khi được gọi là "ngụ ý toàn cục".
function myFunction() {
globalVariable = "global";
return globalVariable
}
myFunction()\
> "global"
globalVariable\
> "global"
Chuyển lên trên biến thiên
Nội dung khai báo biến và hàm được chuyển lên trên đầu phạm vi,
có nghĩa là trình thông dịch JavaScript sẽ xử lý bất kỳ biến nào được khai báo tại bất kỳ
vào một tập lệnh và di chuyển một cách hiệu quả đến dòng đầu tiên của phần bao quanh
trước khi thực thi tập lệnh. Điều này có nghĩa là một biến được khai báo bằng
Có thể tham chiếu var
trước khi khai báo biến mà không gặp phải
lỗi:
hoistedVariable
> undefined
var hoistedVariable;
Vì chỉ lưu trữ phần khai báo biến chứ không phải phần khởi tạo,
các biến chưa được khai báo rõ ràng bằng var
, let
hoặc const
không được di chuyển lên trên:
unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined
unhoistedVariable = true;
Như đã đề cập trước đó, một biến đã khai báo nhưng chưa được khởi tạo
được gán một giá trị undefined
. Hành vi đó áp dụng cho biến được chuyển lên trên
mà chỉ áp dụng cho những khai báo được khai báo bằng var
.
hoistedVariable
> undefined
var hoistedVariable = 2 + 2;
hoistedVariable\
> 4
Hành vi khó hiểu này phần lớn là sự cản trở của các quyết định thiết kế được đưa ra trong các phiên bản JavaScript sớm nhất, và không thể thay đổi được nếu không có rủi ro làm hỏng trang web hiện có.
let
và const
giải quyết hành vi này bằng cách gửi một lỗi khi một
được truy cập trước khi tạo:
{
hoistedVariable;
let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization
Lỗi này khác với lỗi "hoistedVariable không được xác định" lỗi, bạn
có thể xảy ra khi cố gắng truy cập vào một biến chưa được khai báo. Vì JavaScript
đã chuyển biến lên trên, thì biết rằng biến sẽ được tạo trong
phạm vi nhất định. Tuy nhiên, thay vì tạo biến đó trước
có giá trị undefined
thì trình thông dịch sẽ gửi lỗi.
Các biến được khai báo bằng let
hoặc const
(hoặc class
) được xem là tồn tại trong một
"vùng chết tạm thời" ("TDZ") từ đầu khối bao quanh cho đến khi
điểm trong mã nơi biến được khai báo.
Vùng chết tạm thời giúp hành vi của let
trực quan hơn so với var
đối với
tác giả. Điều này cũng rất quan trọng đối với thiết kế của const
. Vì hằng số không thể là
đã thay đổi, một hằng số được chuyển lên đầu phạm vi và được cấp một giá trị ngầm ẩn
sau đó không thể khởi chạy undefined
bằng một giá trị có ý nghĩa.
Kiểm tra kiến thức
Bạn có thể bắt đầu giá trị nhận dạng bằng những loại ký tự nào?
Phương pháp ưu tiên để khai báo biến có giá trị là gì có thể thay đổi bất cứ lúc nào?