Chúng ta biết nhiều toán từ từ trường học. Chúng là những thứ như cộng +, nhân *, trừ -, v.v.

Trong chương này, chúng ta sẽ bắt đầu với các toán tử đơn giản, sau đó tập trung vào các khía cạnh dành riêng cho JavaScript, không thuộc phạm vi số học của trường.

1. Các “unary”, “binary”, “operand”

Trước khi chúng ta tiếp tục, hãy nắm bắt một số thuật ngữ phổ biến.

  • Một toán hạng(operand) – là những gì các toán tử được áp dụng cho. Chẳng hạn, trong phép nhân 5 * 2có hai toán hạng: toán hạng bên trái là 5và toán hạng bên phải là 2. Đôi khi, mọi người gọi những đối số này thay vì các toán hạng khác.
  • Một toán tử là unary nếu nó có một toán hạng duy nhất. Ví dụ: phủ định đơn nguyên -đảo ngược dấu của một số:
let x = 1; x = -x; alert( x ); // -1, unary negation was applied

Một toán tử là nhị phân(binary) nếu nó có hai toán hạng. Điểm tương tự cũng tồn tại ở dạng nhị phân:

let x = 1, y = 3;
alert( y - x ); // 2, binary minus subtracts values
  • Chính thức, trong các ví dụ trên, chúng ta có hai toán tử khác nhau có cùng ký hiệu: toán tử phủ định là toán tử đơn nguyên đảo ngược dấu và toán tử trừ là toán tử nhị phân trừ một số với một số khác.

2. Toán học

Các hoạt động toán học sau được hỗ trợ trong Javascript:

  • Cộng +,
  • Phép trừ -,
  • Nhân *,
  • Chia /,
  • Lấy phần còn lại %,
  • Lũy thừa **.

Bốn cái đầu tiên rất đơn giản, trong khi %**cần một vài từ về chúng.

2.1 Lấy phần còn lại %

Toán tử còn lại %, mặc dù xuất hiện, không liên quan đến phần trăm.

Kết quả a % bphần còn lại của việc chia số nguyên a với b.

Ví dụ:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

alert( 5 % 2 ); // 1, a remainder of 5 divided by 2
alert( 8 % 3 ); // 2, a remainder of 8 divided by 3

2.2 Số mũ **

Toán tử lũy thừa a ** blà nhân b lầnavới chính nó.

Ví dụ:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

alert( 2 ** 2 ); // 4  (2 multiplied by itself 2 times)
alert( 2 ** 3 ); // 8  (2 * 2 * 2, 3 times)
alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2, 4 times)

Về mặt toán học, lũy thừa cũng được xác định cho các số không nguyên. Ví dụ, một căn bậc hai là một số mũ theo 1/2:

alert( 4 ** (1/2) ); // 2 (power of 1/2 is the same as a square root)
alert( 8 ** (1/3) ); // 2 (power of 1/3 is the same as a cubic root)

3. Nối chuỗi với toán tử nhị phân +

Chúng ta hãy đáp ứng các tính năng của các toán tử JavaScript vượt ra ngoài các trường đại học.

Thông thường, các toán tử cộng + áp dụng cho số.

Nhưng, nếu nhị phân +được áp dụng cho các chuỗi, nó hợp nhất (nối) chúng:

let s = "my" + "string";
alert(s); // mystring

Lưu ý rằng nếu bất kỳ toán hạng nào là một chuỗi, thì một toán hạng khác cũng được chuyển đổi thành một chuỗi.

Ví dụ:

alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"

Xem, không quan trọng là toán hạng thứ nhất là chuỗi hay chuỗi thứ hai.

Đây là một ví dụ phức tạp hơn:

alert(2 + 2 + '1' ); // "41" and not "221"

Ở đây, các toán tử làm việc với Số đầu tiên tính +tổng hai số, vì vậy nó trả về 4, sau đó số tiếp theo +thêm chuỗi 1vào nó, vì vậy nó sẽ là 4 + '1' = 41.

Toán tử Nhị phân +là toán tử duy nhất hỗ trợ các chuỗi theo cách như vậy. Các toán tử số học khác chỉ làm việc với các số và luôn chuyển đổi toán hạng của chúng thành các số.

Đây là bản demo cho phép trừ và chia:

alert( 6 - '2' ); // 4, converts '2' to a number
alert( '6' / '2' ); // 3, converts both operands to numbers

4. Chuyển đổi số với toán tử đơn nguyên +

Dấu cộng +tồn tại ở hai dạng: dạng nhị phân mà chúng ta đã sử dụng ở trên và dạng đơn nguyên.

Phép cộng hay nói cách khác, toán tử cộng +được áp dụng cho một giá trị duy nhất. Nhưng nếu toán hạng không phải là một số, thì unary + sẽ chuyển nó thành một số.

Ví dụ:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

// No effect on numbers
let x = 1;
alert( +x ); // 1

let y = -2;
alert( +y ); // -2

// Converts non-numbers
alert( +true ); // 1
alert( +"" );   // 0

Nó thực sự làm điều tương tự Number(...), nhưng ngắn hơn.

Nhu cầu chuyển đổi chuỗi thành số phát sinh rất thường xuyên. Ví dụ: nếu chúng ta đang nhận các giá trị từ các trường biểu mẫu HTML, thì chúng thường là các chuỗi. Nếu chúng ta muốn tổng hợp chúng thì sao?

Phép cộng nhị phân sẽ thêm chúng dưới dạng chuỗi:

let apples = "2";
let oranges = "3";

alert( apples + oranges ); // "23", the binary plus concatenates strings

Nếu chúng ta muốn coi chúng là số, chúng ta cần chuyển đổi và sau đó tổng hợp chúng:

let apples = "2";
let oranges = "3";

// both values converted to numbers before the binary plus
alert( +apples + +oranges ); // 5

// the longer variant
// alert( Number(apples) + Number(oranges) ); // 5

Từ quan điểm của một nhà toán học, sự phong phú của các điểm cộng có vẻ lạ. Nhưng theo quan điểm của một lập trình viên, không có gì đặc biệt: các phép cộng đơn được áp dụng trước tiên, họ chuyển đổi chuỗi thành số và sau đó toán tử + nhị phân cộng lại.

Tại sao các phép cộng unary được áp dụng cho các giá trị trước các phép nhị phân? Như chúng ta sẽ thấy, đó là vì ưu tiên cao hơn của nó.

5. Toán tử Ưu tiên

Nếu một biểu thức có nhiều toán tử, thứ tự thực hiện được xác định theo mức độ ưu tiên của chúng, hay nói cách khác, thứ tự ưu tiên mặc định của các toán tử.

Từ trường học, tất cả chúng ta đều biết rằng phép nhân trong biểu thức 1 + 2 * 2 đươck thực hiện trước. Đó chính xác là điều ưu tiên. Phép nhân được cho là có độ ưu tiên cao hơn phép cộng.

Dấu ngoặc đơn ghi đè bất kỳ quyền ưu tiên nào, vì vậy nếu chúng ta không hài lòng với thứ tự mặc định, chúng ta có thể sử dụng chúng để thay đổi. Ví dụ, viết (1 + 2) * 2.

Có nhiều toán tử trong JavaScript. Mỗi toán tử có một số ưu tiên tương ứng. Người có độ ưu tiên lớn hơn sẽ thực hiện ở đầu tiên. Nếu quyền ưu tiên là như nhau, thứ tự thực hiện là từ trái sang phải.

Đây là một trích xuất từ bảng ưu tiên (bạn không cần phải nhớ điều này, nhưng lưu ý rằng các toán tử đơn nguyên cao hơn các toán tử nhị phân tương ứng):

Quyền ưu tiênTênKý tên
17cộng đơn+
17phủ định đơn phương-
16lũy thừa**
15phép nhân*
15chia/
13phép cộng+
13phép trừ-
3gán=

Như chúng ta có thể thấy, các phép cộng đơn phân có mức độ ưu tiên 17cao hơn so với các phép cộng 13 (cộng với nhị phân). Đó là lý do tại sao, trong biểu thức "+ apples + + oranges", dấu cộng đơn nguyên hoạt động trước phép cộng.

6. Toán tử gán

Hãy lưu ý rằng gán =cũng là một toán tử. Nó được liệt kê trong bảng ưu tiên với mức độ ưu tiên rất thấp 3.

Đó là lý do tại sao, khi chúng ta gán một biến, như x = 2 * 2 + 1, các phép tính được thực hiện trước và sau đó =được ước tính, lưu trữ kết quả vào x.

let x = 2 * 2 + 1;

alert( x ); // 5

7. Chuyển nhượng = trả về một giá trị

Thực tế =là một toán tử, không phải là một cấu trúc ngôn ngữ có một hàm ý thú vị.

Hầu hết các toán tử trong JavaScript trả về một giá trị. Điều đó rõ ràng cho +-, nhưng cũng đúng cho =.

Gọi x = valuelà gánvaluevào x và sau đó trả lại nó .

Đây là bản demo sử dụng toán tử gán như một phần của biểu thức phức tạp hơn:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

let a = 1;
let b = 2;

let c = 3 - (a = b + 1);

alert( a ); // 3
alert( c ); // 0

Trong ví dụ trên, kết quả của biểu thức (a = b + 1)là giá trị được gán cho a(đó là 3). Sau đó nó được sử dụng để đánh giá thêm.

Chúng ta nên hiểu cách thức hoạt động của nó, bởi vì đôi khi chúng ta thấy nó trong các thư viện JavaScript.

Mặc dù, xin đừng viết code như thế. Những thủ thuật như vậy chắc chắn không làm cho code rõ ràng hơn hoặc có thể đọc được.

8. Một chuỗi toán tử gán

Một tính năng thú vị khác là khả năng xâu chuỗi các biến:

let a, b, c;

a = b = c = 2 + 2;

alert( a ); // 4
alert( b ); // 4
alert( c ); // 4

Một chuỗi toán tử gán được đánh giá từ phải sang trái. Đầu tiên, biểu thức ngoài cùng bên phải 2 + 2được ước tính và sau đó được gán cho các biến ở bên trái : c, ba. Cuối cùng, tất cả các biến chia sẻ một giá trị duy nhất.

Một lần nữa, với mục đích dễ đọc, tốt hơn là chia code vậy thành một vài dòng:

c = 2 + 2;
b = c;
a = c;

Điều đó dễ đọc hơn, đặc biệt là khi quét code nhanh.

9. Sửa đổi tại chỗ

Chúng ta thường cần áp dụng một toán tử cho một biến và lưu trữ kết quả mới trong cùng một biến đó.

Ví dụ:

let n = 2;
n = n + 5;
n = n * 2;

Ký hiệu này có thể được rút ngắn bằng cách sử dụng các toán tử +=*=:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/

let n = 2;
n += 5; // now n = 7 (same as n = n + 5)
n *= 2; // now n = 14 (same as n = n * 2)

alert( n ); // 14

“sửa đổi-và-gán” khai thác tồn tại cho tất cả các toán tử số học và Bitwise: /=, -=vv

Các toán tử như vậy có cùng mức ưu tiên như một phép gán thông thường, vì vậy chúng chạy sau hầu hết các phép tính khác:

let n = 2;

n *= 3 + 5;

alert( n ); // 16  (right part evaluated first, same as n *= 8)

10. Toán tử Tăng giảm

Tăng hoặc giảm một số là một trong những thao tác số phổ biến nhất.

Vì vậy, có các toán tử đặc biệt cho nó:

  • Tăng ++ tăng một biến lên 1:
let counter = 2; counter++;        // works the same as counter = counter + 1, but is shorter alert( counter ); // 3

Giảm -- giảm một biến xuống 1:

let counter = 2;
counter--;        // works the same as counter = counter - 1, but is shorter
alert( counter ); // 1

Quan trọng:

Tăng / giảm chỉ có thể được áp dụng cho các biến. Cố gắng sử dụng nó trên một giá trị như 5++sẽ cho một lỗi.

Các toán tử ++--có thể được đặt trước hoặc sau một biến.

  • Khi toán tử đi sau biến, nó ở dạng hậu tố : counter++.
  • Hình thứ Tiền tố của người dùng là một khi toán tử đi trước biến : ++counter.

Cả hai câu lệnh này đều làm cùng một điều: tăng countertheo 1.

Có sự khác biệt nào không? Có, nhưng chúng ta chỉ có thể nhìn thấy nó nếu chúng ta sử dụng giá trị trả về của ++/--.

Hãy làm rõ. Như chúng ta biết, tất cả các toán tử trả về một giá trị. Tăng / giảm cũng không ngoại lệ. Biểu mẫu tiền tố trả về giá trị mới trong khi biểu mẫu hậu tố trả về giá trị cũ (trước khi tăng / giảm).

Để thấy sự khác biệt, đây là một ví dụ:

let counter = 1;
let a = ++counter; // (*)

alert(a); // 2

Trong dòng (*), mẫu tiền tố++counter tăng countervà trả về giá trị mới , 2. Vì vậy, các alert2.

Bây giờ, hãy sử dụng mẫu hậu tố:


let counter = 1;
let a = counter++; // (*) changed ++counter to counter++

alert(a); // 1

Trong dòng (*), hình thức hậu tốcounter++ cũng tăng counternhưng trả về giá trị (trước khi tăng). Vì vậy, các alerthiển thị là 1.

Để tóm tắt:

  • Nếu kết quả tăng / giảm không được sử dụng, không có sự khác biệt trong hình thức sử dụng:
let counter = 0; counter++; ++counter; alert( counter ); // 2, the lines above did the same

Nếu chúng ta muốn tăng giá trị sử dụng ngay kết quả của toán tử, chúng ta cần mẫu tiền tố:

let counter = 0;
alert( ++counter ); // 1

Nếu chúng ta muốn tăng một giá trị nhưng sử dụng giá trị trước đó, chúng ta cần biểu mẫu hậu tố:

let counter = 0;
alert( counter++ ); // 0

Tăng / giảm giữa các toán tử khác.

Các toán tử ++/--có thể được sử dụng bên trong các biểu thức là tốt. Ưu tiên của nó cao hơn hầu hết các hoạt động số học khác.

Ví dụ:

let counter = 1;
alert( 2 * ++counter ); // 4

So sánh với:

let counter = 1;
alert( 2 * counter++ ); // 2, because counter++ returns the "old" value

Mặc dù về mặt kỹ thuật thì ổn, ký hiệu như vậy thường làm cho code khó đọc hơn. Một dòng làm nhiều việc là không tốt.

Trong khi đọc code, quét mắt nhanh dọc thẳng có thể dễ dàng bỏ lỡ thứ gì đó giống như counter++và không rõ ràng là biến tăng lên.

Chúng tôi tư vấn cho một phong cách cứ một dòng là một hành động

let counter = 1;
alert( 2 * counter );
counter++;

11. Toán tử bitwise

Toán tử bitwise coi các đối số là số nguyên 32 bit và hoạt động ở mức độ biểu diễn nhị phân của chúng.

Các toán tử này không dành riêng cho JavaScript. Chúng được hỗ trợ trong hầu hết các ngôn ngữ lập trình.

Danh sách các toán tử:

  • AND ( &)
  • OR ( |)
  • XOR ( ^)
  • NOT ( ~)
  • Dịch sang trái ( <<)
  • Dịch sang phải ( >>)
  • Lấp đây số 0 và dịch sang phải ( >>>)

Các toán tử này được sử dụng rất hiếm khi chúng ta cần sử dụng các số ở mức rất thấp (bitwise). Chúng ta sẽ không cần biết các toán tử này sớm, vì phát triển web ít sử dụng chúng, nhưng trong một số lĩnh vực đặc biệt, chẳng hạn như mật mã, chúng rất hữu ích. Bạn có thể đọc bài viết Toán tử Bitwise trên MDN khi có nhu cầu.

12. Dấu phẩy

Toán tử dấu phẩy ,là một trong những toán tử hiếm nhất và bất thường nhất. Đôi khi, nó được sử dụng để viết code ngắn hơn, vì vậy chúng ta cần biết nó để hiểu những gì đang xảy ra.

Toán tử dấu phẩy cho phép chúng ta đánh giá một số biểu thức, chia chúng bằng dấu phẩy ,. Mỗi phần tử trong số nó được đánh giá nhưng chỉ có kết quả của người cuối cùng được trả về.

Ví dụ:

let a = (1 + 2, 3 + 4);

alert( a ); // 7 (the result of 3 + 4)

Ở đây, biểu thức đầu tiên 1 + 2được đánh giá và kết quả của nó bị ném đi. Sau đó, 3 + 4được đánh giá và trả lại như là kết quả.

Dấu phẩy có độ ưu tiên rất thấp

Xin lưu ý rằng toán tử dấu phẩy có độ ưu tiên rất thấp, thấp hơn =, vì vậy dấu ngoặc đơn rất quan trọng trong ví dụ trên.

Không có chúng: a = 1 + 2, 3 + 4đánh giá +đầu tiên, tổng hợp các số thành a = 3, 7, sau đó toán tử gán = sẽ gán a = 3và phần còn lại được bỏ qua. Nó giống như (a = 1 + 2), 3 + 4.

Tại sao chúng ta cần một toán tử loại bỏ mọi thứ trừ biểu thức cuối cùng?

Đôi khi, mọi người sử dụng nó trong các cấu trúc phức tạp hơn để đặt một số hành động trong một dòng.

Ví dụ:


// three operations in one line
for (a = 1, b = 3, c = a * b; a < 10; a++) {
 ...
}

Các thủ thuật như vậy được sử dụng trong nhiều framework JavaScript. Đó là lý do tại sao chúng tôi đề cập đến chúng. Nhưng thường thì họ không cải thiện khả năng đọc code vì vậy chúng ta nên suy nghĩ kỹ trước khi sử dụng chúng.

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!