034.3 Bài 1
Chứng chỉ: |
Web Development Essentials |
---|---|
Phiên bản: |
1.0 |
Chủ đề: |
034 Lập trình JavaScript |
Mục tiêu: |
034.3 Cấu trúc và Hàm Điều khiển trong JavaScript |
Bài học: |
1 trên 2 |
Giới thiệu
Giống như bất kỳ mootj ngôn ngữ lập trình nào khác, JavaScript là một tập hợp các câu lệnh cho trình thông dịch lệnh biết phải làm gì theo một thứ tự nhất định. Tuy nhiên, điều này không có nghĩa là mọi câu lệnh chỉ được thực thi một lần hoặc phải được thực thi trong mọi trường hợp. Hầu hết các câu lệnh sẽ chỉ được thực thi khi các điều kiện cụ thể được đáp ứng. Ngay cả khi một tệp lệnh được kích hoạt không đồng bộ bởi các sự kiện độc lập, nó thường sẽ phải kiểm tra một số biến điều khiển để tìm ra phần mã phù hợp để chạy.
Câu lệnh If
Cấu trúc điều khiển đơn giản nhất được cung cấp bởi lệnh if
. Lệnh này sẽ thực thi câu lệnh ngay sau nó nếu điều kiện được chỉ định là đúng. JavaScript coi các điều kiện là đúng khi giá trị được xác định là khác không (0). Bất cứ điều gì bên trong dấu ngoặc đơn sau từ if
(khoảng trắng sẽ được bỏ qua) sẽ được hiểu là một điều kiện. Trong ví dụ sau, chữ số 1
chính là điều kiện:
if ( 1 ) console.log("1 is always true");
Tropng ví dụ này, số 1
đã được viết rõ ràng trong điều kiện; do đó, nó được coi là một giá trị không đổi (giá trị này sẽ không thay đổi trong suốt quá trình thực thi tệp lệnh) và sẽ luôn cho kết quả đúng khi được sử dụng làm biểu thức điều kiện. Từ true
(không có dấu trích dẫn) cũng có thể được sử dụng thay cho 1
vì nó cũng được ngôn ngữ coi là giá trị đúng theo nghĩa đen. Lệnh console.log
sẽ in các đối số của nó trong cửa sổ giao diện điều khiển của trình duyệt.
Tip
|
Bảng điều khiển trình duyệt đã hiển thị lỗi, cảnh báo và thông báo thông tin được gửi qua lệnh |
Mặc dù đúng về mặt cú pháp, việc sử dụng các biểu thức hằng số trong các điều kiện thường không hữu ích lắm. Trong một ứng dụng thực tế, có thể ta sẽ muốn kiểm tra tính đúng đắn của một biến:
let my_number = 3;
if ( my_number ) console.log("The value of my_number is", my_number, "and it yields true");
Giá trị được gán cho biến my_number
(3
) là khác không; vì vậy, giá trị này trả về giá trị đúng. Nhưng ví dụ này không phải là cách sử dụng phổ biến bởi ta sẽ hiếm khi cần kiểm tra xem một số có bằng 0 hay không. Việc so sánh một giá trị này với một giá trị khác và kiểm tra xem kết quả có đúng hay không thường phổ biến hơn rất nhiều:
let my_number = 3;
if ( my_number == 3 ) console.log("The value of my_number is", my_number, "indeed");
Toán tử so sánh bằng kép được sử dụng vì toán tử bằng đơn đã được định nghĩa là toán tử gán. Giá trị ở mỗi bên của toán tử được gọi là toán hạng. Thứ tự của toán hạng không quá quan trọng và bất kỳ biểu thức nào trả về giá trị đều có thể là toán hạng. Dưới đây là danh sách các toán tử so sánh có sẵn khác:
value1 == value2
-
Đúng nếu
value1
bằng vớivalue2
. value1 != value2
-
Đúng nếu
value1
không bằng vớivalue2
. value1 < value2
-
Đúng nếu
value1
nhỏ hơnvalue2
. value1 > value2
-
Đúng nếu
value1
lớn hơnvalue2
. value1 <= value2
-
Đúng nếu
value1
nhỏ hơn hoặc bằngvalue2
. value1 >= value2
-
Đúng nếu
value1
lớn hơn hoặc bằngvalue2
.
Thông thường, không nhất thiết toán hạng bên trái của toán tử phải là một chuỗi và toán hạng bên phải phải là một số, miễn là JavaScript có thể chuyển đổi biểu thức thành một phép so sánh có ý nghĩa. Vì vậy, chuỗi chứa ký tự 1
sẽ được coi là số 1 khi so sánh với một biến số. Để đảm bảo rằng biểu thức chỉ cho kết quả đúng nếu cả hai toán hạng có cùng loại và giá trị, ta nên sử dụng toán tử nhận dạng nghiêm ngặt ===
thay vì ==
. Tương tự như vậy, toán tử không nhận dạng nghiêm ngặt !==
sẽ đánh giá là đúng nếu toán hạng đầu tiên không cùng loại và cùng giá trị với toán tử thứ hai.
Cấu trúc điều khiển if
có thể thực thi theo tuỳ chọn một câu lệnh thay thế khi biểu thức đánh giá là sai :
let my_number = 4;
if ( my_number == 3 ) console.log("The value of my_number is 3");
else console.log("The value of my_number is not 3");
Lệnh else
phải theo ngay sau lệnh if
. Cho đến nay, chúng ta chỉ mới thực hiện một câu lệnh khi điều kiện được đáp ứng. Để thực hiện nhiều hơn một câu lệnh, ta phải đặt chúng trong dấu ngoặc nhọn:
let my_number = 4;
if ( my_number == 3 )
{
console.log("The value of my_number is 3");
console.log("and this is the second statement in the block");
}
else
{
console.log("The value of my_number is not 3");
console.log("and this is the second statement in the block");
}
Một nhóm gồm một hoặc nhiều câu lệnh được phân tách bằng một cặp dấu ngoặc nhọn được gọi là câu lệnh khối. Người ta thường sử dụng các câu lệnh khối ngay cả khi chỉ có một lệnh để thực thi, nhằm đảm bảo kiểu mã hóa nhất quán trong toàn bộ tệp lệnh. Hơn nữa, JavaScript không yêu cầu dấu ngoặc nhọn hoặc bất kỳ câu lệnh nào phải nằm trên các dòng riêng biệt, nhưng làm như vậy sẽ cải thiện khả năng đọc và giúp việc bảo trì mã trở nên dễ dàng hơn.
Các cấu trúc điều khiển có thể được lồng vào nhau, nhưng điều quan trọng là không trộn lẫn các dấu ngoặc nhọn mở và đóng của mỗi câu lệnh khối:
let my_number = 4;
if ( my_number > 0 )
{
console.log("The value of my_number is positive");
if ( my_number % 2 == 0 )
{
console.log("and it is an even number");
}
else
{
console.log("and it is an odd number");
}
} // end of if ( my_number > 0 )
else
{
console.log("The value of my_number is less than or equal to 0");
console.log("and I decided to ignore it");
}
Các biểu thức được đánh giá bởi lệnh if
có thể sẽ phức tạp hơn các phép so sánh đơn giản. Điều này đúng trong trường hợp của ví dụ trước, trong đó biểu thức số học my_number % 2
được sử dụng bên trong dấu ngoặc đơn của lệnh if
được lồng vào. Toán tử %
sẽ trả về số dư sau khi chia số bên trái cho số bên phải. Các toán tử số học như %
sẽ được ưu tiên hơn các toán tử so sánh như ==
; do đó, phép so sánh sẽ sử dụng kết quả của biểu thức số học làm toán hạng bên trái của nó.
Trong nhiều trường hợp, các cấu trúc điều kiện lồng nhau có thể được kết hợp thành một cấu trúc duy nhất bằng cách sử dụng các toán tử logic. Ví dụ: nếu chỉ quan tâm đến các số chẵn dương, ta có thể sử dụng một cấu trúc if
duy nhất:
let my_number = 4;
if ( my_number > 0 && my_number % 2 == 0 )
{
console.log("The value of my_number is positive");
console.log("and it is an even number");
}
else
{
console.log("The value of my_number either 0, negative");
console.log("or it is a negative number");
}
Toán tử dấu và kép &&
trong biểu thức được đánh giá là toán tử logic AND. Nó chỉ tính là đúng nếu biểu thức bên trái của nó và biểu thức bên phải của nó tính là đúng. Nếu muốn so khớp các số dương hoặc số chẵn, toán tử ||
nên được sử dụng thay thế (viết tắt của toán tử logic OR):
let my_number = -4;
if ( my_number > 0 || my_number % 2 == 0 )
{
console.log("The value of my_number is positive");
console.log("or it is a even negative number");
}
Trong ví dụ này, chỉ các số lẻ âm sẽ không khớp với tiêu chí do biểu thức tổng hợp đặt ra. Nếu muốn làm ngược lại, tức là chỉ khớp với các số lẻ âm, hãy thêm toán tử logic NOT !
vào đầu biểu thức:
let my_number = -5;
if ( ! ( my_number > 0 || my_number % 2 == 0 ) )
{
console.log("The value of my_number is an odd negative number");
}
Việc thêm dấu ngoặc đơn vào biểu thức tổng hợp sẽ buộc hệ thống tính biểu thức bên trong nó trước. Nếu không có các dấu ngoặc đơn này, toán tử NOT sẽ chỉ áp dụng cho my_number > 0
và khi đó biểu thức OR sẽ được tính. Toán tử &&
và ||
được gọi là toán tử logic nhị phân vì chúng yêu cầu hai toán hạng. !
được coi như một toán tử logic một ngôi bởi nó chỉ yêu cầu một toán hạng.
Cấu trúc Chuyển
Mặc dù cấu trúc if
khá là linh hoạt và đủ để kiểm soát luồng của chương trình, cấu trúc điều khiển switch
có thể sẽ phù hợp hơn khi cần tính các kết quả không phải đúng hoặc sai. Ví dụ: nếu chúng ta muốn thực hiện một hành động riêng biệt cho từng mục được chọn từ danh sách, ta sẽ cần viết cấu trúc if
cho mỗi một đánh giá:
// Available languages: en (English), es (Spanish), pt (Portuguese)
let language = "pt";
// Variable to register whether the language was found in the list
let found = 0;
if ( language == "en" )
{
found = 1;
console.log("English");
}
if ( found == 0 && language == "es" )
{
found = 1;
console.log("Spanish");
}
if ( found == 0 && language == "pt" )
{
found = 1;
console.log("Portuguese");
}
if ( found == 0 )
{
console.log(language, " is unknown to me");
}
Trong ví dụ này, một biến phụ trợ found
sẽ được sử dụng bởi tất cả các cấu trúc if
để tìm hiểu xem có xảy ra một kết quả khớp hay không. Trong trường hợp này, cấu trúc switch
sẽ thực hiện nhiệm vụ tương tự nhưng theo một cách ngắn gọn hơn:
switch ( language )
{
case "en":
console.log("English");
break;
case "es":
console.log("Spanish");
break;
case "pt":
console.log("Portuguese");
break;
default:
console.log(language, " not found");
}
Mỗi lệnh case
được lồng vào sẽ được gọi là một mệnh đề. Khi một mệnh đề khớp với biểu thức được đánh giá, nó sẽ thực thi các câu lệnh theo sau dấu hai chấm cho đến câu lệnh break
. Mệnh đề cuối cùng sẽ không cần câu lệnh break
và thường được sử dụng để thiết lập hành động mặc định khi không có kết quả khớp nào khác xảy ra. Như đã thấy trong ví dụ, cấu trúc switch
không cần biến phụ trợ.
Warning
|
|
Nếu có nhiều hơn một mệnh đề kích hoạt cùng một hành động, ta có thể kết hợp hai hoặc nhiều điều kiện case
:
switch ( language )
{
case "en":
case "en_US":
case "en_GB":
console.log("English");
break;
case "es":
console.log("Spanish");
break;
case "pt":
case "pt_BR":
console.log("Portuguese");
break;
default:
console.log(language, " not found");
}
Vòng lặp
Trong các ví dụ trước, cấu trúc if
và switch
rất phù hợp cho các tác vụ chỉ cần chạy một lần sau khi vượt qua một hoặc nhiều bài kiểm tra có điều kiện. Tuy nhiên, có những tình huống khi một tác vụ phải thực thi lặp đi lặp lại — trong cái được gọi là vòng lặp (loop) — miễn là biểu thức điều kiện của nó vẫn là đúng. Ví dụ như nếu cần biết một số có phải là số nguyên tố hay không, ta sẽ cần kiểm tra xem liệu phép chia số này cho bất kỳ số nguyên nào lớn hơn 1 và nhỏ hơn chính nó có số dư bằng 0 hay không. Nếu đúng, số đó có thừa số nguyên và nó không phải là số nguyên tố (đây không phải là một phương pháp nghiêm ngặt hoặc hiệu quả để tìm các số nguyên tố - đây chỉ là một ví dụ đơn giản). Các cấu trúc điều khiển vòng lặp sẽ phù hợp hơn cho những trường hợp như vậy, đặc biệt là câu lệnh while
:
// A naive prime number tester
// The number we want to evaluate
let candidate = 231;
// Auxiliary variable
let is_prime = true;
// The first factor to try
let factor = 2;
// Execute the block statement if factor is
// less than candidate and keep doing it
// while factor is less than candidate
while ( factor < candidate )
{
if ( candidate % factor == 0 )
{
// The remainder is zero, so the candidate is not prime
is_prime = false;
break;
}
// The next factor to try. Simply
// increment the current factor by one
factor++;
}
// Display the result in the console window.
// If candidate has no integer factor, then
// the auxiliary variable is_prime still true
if ( is_prime )
{
console.log(candidate, "is prime");
}
else
{
console.log(candidate, "is not prime");
}
Câu lệnh khối sau lệnh while
sẽ thực thi lặp đi lặp lại, miễn là điều kiện factor < candidate
vẫn đúng. Nó sẽ thực thi ít nhất một lần, miễn là ta khởi tạo biến factor
với giá trị thấp hơn candidate
(ứng viên). Cấu trúc if
được lồng trong cấu trúc while
sẽ đánh giá xem số dư của candidate
chia cho factor
có bằng 0 hay không. Nếu đúng, số ứng viên không phải là số nguyên tố và vòng lặp có thể kết thúc. Câu lệnh break
sẽ kết thúc vòng lặp và quy trình thực thi sẽ chuyển sang lệnh đầu tiên sau khối while
.
Hãy lưu ý rằng kết quả của điều kiện được sử dụng bởi câu lệnh while
phải thay đổi ở mọi vòng lặp; nếu không, câu lệnh khối sẽ lặp đi lặp lại “mãi mãi”. Trong ví dụ này, chúng ta tăng biến factor
‒ước số tiếp theo mà chúng ta muốn thử‒và nó sẽ đảm bảo vòng lặp sẽ kết thúc tại một thời điểm nào đó.
Phần triển khai đơn giản này của trình kiểm tra số nguyên tố đã hoạt động như mong đợi. Tuy nhiên, chúng ta biết rằng một số không chia hết cho hai sẽ không chia hết cho bất kỳ số chẵn nào khác. Do đó, chúng ta có thể bỏ qua các số chẵn bằng cách thêm một lệnh if
khác:
while ( factor < candidate )
{
// Skip even factors bigger than two
if ( factor > 2 && factor % 2 == 0 )
{
factor++;
continue;
}
if ( candidate % factor == 0 )
{
// The remainder is zero, so the candidate is not prime
is_prime = false;
break;
}
// The next number that will divide the candidate
factor++;
}
Câu lệnh continue
tương tự như câu lệnh break
, nhưng thay vì kết thúc lần lặp này của vòng lặp, nó sẽ bỏ qua phần còn lại của khối vòng lặp và bắt đầu một lần lặp mới. Hãy lưu ý rằng biến factor
đã được sửa đổi trước câu lệnh continue
; nếu không, vòng lặp sẽ lại có kết quả tương tự trong lần lặp tiếp theo. Ví dụ này quá đơn giản và việc bỏ qua một phần của vòng lặp sẽ không thực sự cải thiện hiệu suất của nó; nhưng việc bỏ qua các lệnh dư thừa là rất quan trọng khi ta muốn viết các ứng dụng hiệu quả.
Các vòng lặp được sử dụng phổ biến đến mức chúng tồn tại ở nhiều biến thể khác nhau. Vòng lặp for
đặc biệt thích hợp để lặp qua các giá trị tuần tự vì nó cho phép ta xác định quy tắc vòng lặp trong một dòng:
for ( let factor = 2; factor < candidate; factor++ )
{
// Skip even factors bigger than two
if ( factor > 2 && factor % 2 == 0 )
{
continue;
}
if ( candidate % factor == 0 )
{
// The remainder is zero, so the candidate is not prime
is_prime = false;
break;
}
}
Ví dụ này sẽ tạo ra kết quả y hệt như ví dụ while
trước đó, nhưng biểu thức trong ngoặc đơn của nó bao gồm ba phần được phân tách bằng dấu chấm phẩy: khởi tạo (let factor = 2
), điều kiện vòng lặp (factor < candidate
) và biểu thức cuối cùng được đánh giá ở cuối mỗi lần lặp lại vòng lặp (factor+`). Câu lệnh `continue` và `break` cũng áp dụng cho các vòng lặp `for`. Biểu thức cuối cùng trong ngoặc đơn (`factor+
) sẽ được đánh giá sau câu lệnh continue
; do đó, nó không được nằm trong câu lệnh khối; nếu không, nó sẽ được tăng lên hai lần trước lần lặp tiếp theo.
JavaScript có các loại vòng lặp for
đặc biệt để xử lý các đối tượng dạng mảng. Ví dụ như chúng ta có thể kiểm tra một mảng của các biến ứng viên thay vì chỉ một biến:
// A naive prime number tester
// The array of numbers we want to evaluate
let candidates = [111, 139, 293, 327];
// Evaluates every candidate in the array
for (candidate of candidates)
{
// Auxiliary variable
let is_prime = true;
for ( let factor = 2; factor < candidate; factor++ )
{
// Skip even factors bigger than two
if ( factor > 2 && factor % 2 == 0 )
{
continue;
}
if ( candidate % factor == 0 )
{
// The remainder is zero, so the candidate is not prime
is_prime = false;
break;
}
}
// Display the result in the console window
if ( is_prime )
{
console.log(candidate, "is prime");
}
else
{
console.log(candidate, "is not prime");
}
}
Câu lệnh for (candidate of candidate)
sẽ gán một phần tử của mảng candidates
cho biến candidate
, sử dụng nó trong câu lệnh khối và lặp lại quy trình cho mọi phần tử trong mảng. Ta không cần khai báo cho riêng candidate
vì vòng lặp for
sẽ xác định nó. Cuối cùng, mã từ ví dụ trước được lồng trong câu lệnh khối mới này, nhưng lần này, nó sẽ kiểm tra từng ứng viên trong mảng.
Bài tập Hướng dẫn
-
Giá trị nào của biến
my_var
phù hợp với điều kiệnmy_var > 0 && my_var < 9
? -
Giá trị nào của biến
my_var
phù hợp với điều kiệnmy_var > 0 || my_var < 9
? -
Vòng lặp
while
sau đây thực thi câu lệnh khối của nó bao nhiêu lần?let i = 0; while ( 1 ) { if ( i == 10 ) { continue; } i++; }
Bài tập Mở rộng
-
Điều gì sẽ xảy ra nếu toán tử gán bằng
=
được sử dụng thay cho toán tử so sánh bằng==
? -
Hãy viết một đoạn mã bằng cách sử dụng cấu trúc điều khiển
if
, trong đó, phép so sánh đẳng thức thông thường sẽ trả về giá trị đúng nhưng phép so sánh đẳng thức nghiêm ngặt sẽ không trả về. -
Hãy viết lại câu lệnh
for
sau bằng cách sử dụng toán tử logic NOT một ngôi trong điều kiện vòng lặp. Kết quả của điều kiện phải giống nhau.for ( let factor = 2; factor < candidate; factor++ )
-
Dựa trên các ví dụ trong bài học này, hãy viết một cấu trúc điều khiển vòng lặp để in ra tất cả các thừa số nguyên của một số đã cho.
Tóm tắt
Bài học này đã trình bày cách sử dụng các cấu trúc điều khiển trong mã JavaScript. Cấu trúc điều kiện và vòng lặp là những yếu tố thiết yếu của bất kỳ mô hình lập trình nào và phát triển web JavaScript cũng không phải là ngoại lệ. Bài học đã đi qua các khái niệm và quy trình sau:
-
Câu lệnh
if
và các toán tử so sánh. -
Cách sử dụng cấu trúc
switch
vớicase
,default
vàbreak
. -
Sự khác biệt giữa so sánh thông thường và so sánh nghiêm ngặt.
-
Các cấu trúc điều khiển vòng lặp:
while
vàfor
.
Đáp án Bài tập Hướng dẫn
-
Giá trị nào của biến
my_var
phù hợp với điều kiệnmy_var > 0 && my_var < 9
?Chỉ các số vừa lớn hơn 0 vừa nhỏ hơn 9. Toán tử logic
&&
(AND) yêu cầu cả hai phép so sánh phải khớp với nhau. -
Giá trị nào của biến
my_var
phù hợp với điều kiệnmy_var > 0 || my_var < 9
?Việc sử dụng toán tử logic
||
(OR) sẽ khiến bất kỳ số nào cũng khớp vì bất kỳ số nào cũng sẽ lớn hơn 0 hoặc nhỏ hơn 9. -
Vòng lặp
while
sau đây thực thi câu lệnh khối của nó bao nhiêu lần?let i = 0; while ( 1 ) { if ( i == 10 ) { continue; } i++; }
Lệnh khối sẽ lặp lại vô thời hạn vì không có điều kiện dừng nào được cung cấp.
Đáp án Bài tập Mở rộng
-
Điều gì sẽ xảy ra nếu toán tử gán bằng
=
được sử dụng thay cho toán tử so sánh bằng==
?Giá trị ở phía bên phải của toán tử sẽ được gán cho biến ở bên trái và kết quả sẽ được chuyển sang phép so sánh; đây có thể không phải là một hành vi được mong muốn.
-
Hãy viết một đoạn mã bằng cách sử dụng cấu trúc điều khiển
if
, trong đó, phép so sánh đẳng thức thông thường sẽ trả về giá trị đúng nhưng phép so sánh đẳng thức nghiêm ngặt sẽ không trả về.let a = "1"; let b = 1; if ( a == b ) { console.log("An ordinary comparison will match."); } if ( a === b ) { console.log("A strict comparison will not match."); }
-
Hãy viết lại câu lệnh
for
sau bằng cách sử dụng toán tử logic NOT đơn hạng trong điều kiện vòng lặp. Kết quả của điều kiện phải giống nhau.for ( let factor = 2; factor < candidate; factor++ )
Đáp án:
for ( let factor = 2; ! (factor >= candidate); factor++ )
-
Dựa trên các ví dụ trong bài học này, hãy viết một cấu trúc điều khiển vòng lặp để in ra tất cả các thừa số nguyên của một số đã cho.
for ( let factor = 2; factor <= my_number; factor++ ) { if ( my_number % factor == 0 ) { console.log(factor, " is an integer factor of ", my_number); } }