Skip to content

Functions #222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ importance: 4

---

# Có thật là từ "else" cần thiết?
# "else" có bắt buộc không

Hàm sau đây sẽ trả về `true` nếu tham số `age` là lớn hơn `18`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ function checkAge(age) {
}
```

Lưu ý rằng dấu ngoặc đơn quanh `age > 18` thì không được yêu cầu ở đây. Chúng tồn tại để dễ hơn cho việc đọc.
Lưu ý rằng dấu ngoặc đơn quanh `age > 18` không bắt buộc. Chúng tồn tại để chúng ta dễ đọc hơn.
2 changes: 1 addition & 1 deletion 1-js/02-first-steps/15-function-basics/3-min/solution.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ function min(a, b) {
}
```

Tái bút: Trong trường hợp có một phương trình `a == b` thì không còn quan trọng việc trả về giá trị gì.
"Tái bút: Trong trường hợp so sánh bằng nhau `a == b` thì không quan trọng giá trị trả về gì."
78 changes: 39 additions & 39 deletions 1-js/02-first-steps/15-function-basics/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

Thông thường chúng ta cần thực hiện một hành động tương tự ở nhiều nơi trong tập lệnh.

Ví dụ: chúng tôi cần hiển thị một thông báo đẹp mắt khi khách hàng truy cập đăng nhập, đăng xuất và có thể ở một nơi khác
Ví dụ: chúng ta cần hiển thị một thông báo đẹp mắt khi khách hàng truy cập đăng nhập, đăng xuất và có thể ở một nơi khác

Các hàm là "khối xây dựng" chính của chương trình. Chúng cho phép đoạn mã được gọi nhiều lần mà không lặp lại.
Các hàm là "khối xây dựng" chính của chương trình. Chúng cho phép chúng ta viết một đoạn mã chỉ một lần nhưng lại có thể thực hiện nó nhiều lần, thay vì phải viết lặp lại đoạn mã đó mỗi khi muốn thực hiện nó.

Chúng ta đã thấy các ví dụ về hàm dựng sẵn, như `alert(message)`, `prompt(message, default)` và `confirm(question)`. Nhưng chúng ta cũng có thể tạo những hàm riêng theo các mục đích khác nhau.

Expand All @@ -20,15 +20,15 @@ function showMessage() {
}
```

Từ khoá `function` được bắt đầu trước, sau đó đến *tên của hàm*, và có một danh sách các *tham số* giữa các dấu ngoặc đơn (được phân tách bằng dấu phẩy, trống trong ví dụ trên) và cuối cùng là mã của hàm, còn được đặt tên là "nội dung của hàm", giữa các dấu ngoặc nhọn.
Từ khoá `function` được bắt đầu trước, sau đó đến *tên của hàm*, và có một danh sách các *tham số* giữa các dấu ngoặc đơn (được phân tách bằng dấu phẩy, những cũng có thể để trống như trong ví dụ trên) và cuối cùng là mã của hàm, còn được đặt tên là "thân hàm", giữa các dấu ngoặc nhọn.

```js
function name(parameters) {
...body...
}
```

Chức năng mới của chúng ta có thể được gọi bằng tên của nó:: `showMessage()`.
Hàm mới của chúng ta có thể được gọi bằng tên của nó:: `showMessage()`.

Ví dụ:

Expand All @@ -43,15 +43,15 @@ showMessage();
*/!*
```

Việc gọi `showMessage()` thực thi đoạn mã trong hàm. Ở đây chúng ta sẽ thấy tin nhắn được hiển thị hai lần.
Việc gọi `showMessage()` thực thi đoạn mã trong hàm. Ở đây chúng ta sẽ thấy thông điệp được hiển thị hai lần.

Ví dụ này thể hiện rõ ràng một trong những mục đích chính của hàm: tránh trùng lặp mã.

Nếu chúng ta cần thay đổi thông báo hoặc cách nó được hiển thị, chỉ cần sửa đổi mã ở một nơi: hàm xuất ra nó là đủ.

## Các biến cục bộ

Một biến được khai báo bên trong một hàm chỉ hiển thị bên trong hàm đó.
Một biến được khai báo bên trong một hàm chỉ nhìn thấy được từ bên trong hàm đó.

Ví dụ:

Expand All @@ -66,7 +66,7 @@ function showMessage() {

showMessage(); // Xin chào, tôi là JavaScript!

alert( message ); // <-- Lỗi! Đây là biến cục bộ so với hàm
alert( message ); // <-- Lỗi! Đây là cục bộ đối với hàm
```

## Các biến bên ngoài
Expand All @@ -84,7 +84,7 @@ function showMessage() {
showMessage(); // Xin chào, John
```

Hàm có toàn quyền truy cập vào biến ngoài. Nó cũng có thể thay đổi được.
Hàm có toàn quyền truy cập vào biến ngoài. Nó cũng có thể thay đổi được biến ngoài.

Ví dụ:

Expand All @@ -105,9 +105,9 @@ showMessage();
alert( userName ); // *!*Bob*/!*, the value was modified by the function
```

Biến ngoài chỉ được sử dụng nếu không có biến cục bộ.
Biến ngoài chỉ được sử dụng nếu không có biến cục bộ trùng tên với nó.

Nếu một biến cùng tên được khai báo bên trong hàm thì nó sẽ *che khuất* biến bên ngoài. Ví dụ: trong đoạn mã bên dưới, hàm sử dụng `userName` cục bộ. Cái bên ngoài bị bỏ qua:
Nếu một biến cùng tên được khai báo bên trong hàm thì nó sẽ *che khuất* biến bên ngoài. Ví dụ: trong đoạn mã bên dưới, hàm sử dụng `userName` cục bộ. Biến bên ngoài bị bỏ qua:

```js run
let userName = 'John';
Expand All @@ -128,11 +128,11 @@ alert( userName ); // *!*John*/!*, unchanged, the function did not access the ou
```

```smart header="Biến toàn cục"
Các biến được khai báo bên ngoài bất kỳ hàm nào, chẳng hạn như `userName` bên ngoài trong mã ở trên, được gọi là *toàn cục*.
Các biến được khai báo bên ngoài bất kỳ hàm nào, chẳng hạn như biến ngoài `userName` trong mã ở trên, được gọi là *toàn cục*.

Các biến toàn cục được hiển thị từ bất kỳ hàm nào (trừ khi bị che bởi cục bộ).
Các biến toàn cục có thể nhìn thấy được từ bất kỳ hàm nào (trừ phi bị che bởi biến cục bộ).

Đó là một cách thực hành tốt để giảm thiểu việc sử dụng các biến toàn cục. Mã nguồn hiện đại có ít hoặc không có toàn cục. Hầu hết các biến đều nằm trong hàm của chúng. Tuy nhiên, đôi khi chúng có thể hữu ích để lưu trữ dữ liệu cấp dự án.
Đó là một cách thực hành tốt giảm thiểu việc sử dụng các biến toàn cục. Mã nguồn hiện đại có ít hoặc không có toàn cục. Hầu hết các biến đều nằm trong hàm của chúng. Tuy nhiên, đôi khi chúng có thể hữu ích để lưu trữ dữ liệu cấp dự án.
```

## Các tham số
Expand All @@ -152,9 +152,9 @@ showMessage('Ann', "Có chuyện gì á?"); // Ann: What's up? (**)
*/!*
```

Khi hàm được gọi trong các dòng `(*)` và `(**)`, các giá trị đã cho sẽ được sao chép sang các biến cục bộ `from` và `text`. Sau đó, chức năng sử dụng chúng.
Khi hàm được gọi trong các dòng `(*)` và `(**)`, các giá trị đã cho sẽ được sao chép sang các biến cục bộ `from` và `text`. Sau đó, hàm sẽ sử dụng chúng.

Đây là một ví dụ nữa: chúng ta có một biến `from` và chuyểnvào hàm. Xin lưu ý: hàm thay đổi `from`, nhưng sự thay đổi không được nhìn thấy bên ngoài, vì hàm luôn nhận được bản sao của giá trị:
Đây là một ví dụ nữa: chúng ta có một biến `from` và truyềncho hàm. Xin lưu ý: hàm thay đổi `from`, nhưng sự thay đổi không được nhìn thấy từ bên ngoài, vì hàm luôn nhận được bản sao của giá trị:


```js run
Expand All @@ -177,7 +177,7 @@ alert( from ); // Ann

## Những giá trị mặc định

Nếu một tham số không được cung cấp thì giá trị của nó sẽ trở thành `không xác định`.
Nếu một tham số không được cung cấp thì giá trị của nó sẽ trở thành `undefined`.

Ví dụ, hàm `showMessage(from, text)` nói trên có thể được gọi bằng một đối số duy nhất:

Expand All @@ -197,9 +197,9 @@ function showMessage(from, *!*text = "không có văn bản nào được đưa
showMessage("Ann"); // Ann: không có văn bản nào được đưa ra
```

Bây giờ nếu tham số `text` không được truyền, nó sẽ nhận giá trị `"không có văn bản"`
Bây giờ nếu tham số `text` không được truyền, nó sẽ nhận giá trị `"không có văn bản nào được đưa ra"`

Ở đây `"không có văn bản nào"` là một chuỗi, nhưng nó có thể là một biểu thức phức tạp hơn, chỉ được đánh giá và gán nếu thiếu tham số. Vì vậy, điều này cũng có thể:
Ở đây `"không có văn bản nào được đưa ra"` là một chuỗi, nhưng nó có thể là một biểu thức phức tạp hơn, chỉ được đánh giá và gán nếu thiếu tham số. Vì vậy, điều này cũng có thể:

```js run
function showMessage(from, text = anotherFunction()) {
Expand All @@ -224,7 +224,7 @@ To check for an omitted parameter, we can compare it with `undefined`:
function showMessage(text) {
*!*
if (text === undefined) {
text = 'tin nhắn trống';
text = 'tin nhắn rỗng';
}
*/!*

Expand Down Expand Up @@ -259,7 +259,7 @@ showCount(); // unknown

## Trả về một giá trị

Kết quả là một hàm có thể trả về một giá trị vào mã gọi.
Một hàm có thể trả về một giá trị làm kết quả cho mã gọi hàm đó.

Ví dụ đơn giản nhất là hàm tính tổng hai giá trị:

Expand All @@ -272,7 +272,7 @@ let result = sum(1, 2);
alert( result ); // 3
```

Lệnh `return` có thể ở bất kỳ vị trí nào của hàm. Khi quá trình thực thi đạt đến mức đó, hàm sẽ dừng và giá trị được trả về mã gọi (được gán cho `kết quả` ở trên).
Lệnh `return` có thể ở bất kỳ vị trí nào của hàm. Khi quá trình thực thi đạt đến mức đó, hàm sẽ dừng và giá trị được trả về mã gọi (được gán cho `result` ở trên).

Có thể có nhiều lần xuất hiện của `return` trong một hàm. Ví dụ:

Expand Down Expand Up @@ -315,18 +315,18 @@ function showMovie(age) {
}
```

Ở đoạn mã ở trên, nếu `checkAge(age)` trả về `false`, sau đó `showMovie` sẽ không dẫn tới `alert`.
Ở đoạn mã ở trên, nếu `checkAge(age)` trả về `false`, thì `showMovie` sẽ không thực hiện hàm `alert`.

````smart header="Một hàm trả về giá trị với `return` hoặc không có gì với `undefined`"
Nếu một hàm không trả về một giá trị thì cũng giống như khi nó trả về `undefined`:
````smart header="Một hàm trả với `return` rỗng hoặc không có `return` thì trả về `undefined`"
Nếu một hàm không trả về một giá trị thì cũng giống như nó trả về `undefined`:

```js run
function doNothing() { /* empty */ }

alert( doNothing() === undefined ); // true
```

Trường hợp `return` thì cũng giống với `return undefined`:
Trường hợp `return` rỗng, không kèm theo giá trị, thì cũng giống với `return undefined`:

```js run
function doNothing() {
Expand All @@ -338,7 +338,7 @@ alert( doNothing() === undefined ); // true
````

````warn header="Không bao giờ thêm dòng mới giữa `return` và giá trị"
Đối với một biểu thức dài trong `return`, có thể nên đặt nó trên một dòng riêng biệt, như thế này:
Đối với một biểu thức dài trong `return`, có thể bạn muốn đặt nó trên một dòng riêng biệt, như thế này:

```js
return
Expand Down Expand Up @@ -369,7 +369,7 @@ Và nó sẽ hoạt động đúng như chúng ta mong đợi.

Các hàm là các hành động. Vì vậy tên của chúng thường là một động từ. Nó phải ngắn gọn, chính xác nhất có thể và mô tả chức năng của hàm để ai đó đọc mã sẽ biết được chức năng của hàm.

Thông lệ phổ biến là bắt đầu một chức năng bằng tiền tố bằng lời nói mô tả hành động một cách mơ hồ. Phải có sự thống nhất trong nhóm về ý nghĩa của các tiền tố.
Thông lệ phổ biến là bắt đầu một hàm bằng tiền tố động từ mô tả mơ hồ hành động của hàm. Phải có sự thống nhất trong nhóm về ý nghĩa của các tiền tố.

Ví dụ: các hàm bắt đầu bằng `"show"` thường hiển thị nội dung nào đó.

Expand All @@ -383,7 +383,7 @@ Chức năng bắt đầu bằng...
Các ví dụ cho những tên kể trên:

```js no-beautify
showMessage(..) // đưa ra một tin nhắn
showMessage(..) // một thông báo (hoặc thông điệp)
getAge(..) // trả về tuổi (lấy nó bằng cách nào đó)
calcSum(..) // tính tổng và trả về kết quả
createForm(..) // tạo một biểu mẫu (và thường trả về nó)
Expand All @@ -393,7 +393,7 @@ checkPermission(..) // kiểm tra quyền, trả về đúng/sai
Với các tiền tố đã có sẵn, chỉ cần nhìn lướt qua tên hàm là bạn sẽ hiểu nó thực hiện loại công việc gì và trả về loại giá trị nào..

```smart header="Một hàm -- một hành động"
Một hàm phải thực hiện chính xác những gì được gợi ý theo tên của nó, không hơn thế nữa.
Một hàm nên thực hiện chính xác những gì được gợi ý theo tên của nó, không làm gì khác nữa.

Hai hành động độc lập thường xứng đáng có hai hàm, ngay cả khi chúng thường được gọi cùng nhau (trong trường hợp đó chúng ta có thể tạo hàm thứ 3 gọi hai hàm đó).

Expand All @@ -403,22 +403,22 @@ Một vài ví dụ về việc vi phạm quy tắc này:
- `createForm` -- sẽ rất tệ nếu nó sửa đổi tài liệu, thêm biểu mẫu vào đó (chỉ nên tạo và trả về).
- `checkPermission` -- sẽ rất tệ nếu nó hiển thị thông báo `quyền truy cập được cấp/từ chối` (chỉ nên thực hiện kiểm tra và trả về kết quả).

Những ví dụ này giả định ý nghĩa chung của tiền tố. Bạn và nhóm của bạn có thể tự do đồng ý về các ý nghĩa khác, nhưng thông thường chúng không khác nhau nhiều. Trong mọi trường hợp, bạn phải hiểu rõ ý nghĩa của tiền tố, hàm có tiền tố có thể và không thể làm gì. Tất cả các hàm có tiền tố giống nhau phải tuân theo các quy tắc. Và nhóm nên chia sẻ kiến ​​thức.
Những ví dụ này giả định ý nghĩa chung của tiền tố. Bạn và nhóm của bạn có thể tự do đồng ý về các ý nghĩa khác, nhưng thông thường chúng không khác nhau nhiều. Trong mọi trường hợp, bạn phải hiểu rõ ý nghĩa của tiền tố, hàm có tiền tố có thể và không thể làm gì. Tất cả các hàm có tiền tố giống nhau phải tuân theo các quy tắc. Và nhóm nên có chung nhận ​​thức.
```

```smart header="Những tên hàm siêu ngắn"
Các hàm được sử dụng *rất thường xuyên* đôi khi có tên cực ngắn.

Ví dụ: khung [jQuery](http://jquery.com) xác định một hàm `$`. Thư viện [Lodash](http://lodash.com/) có chức năng cốt lõi được đặt tên là `_`.
Ví dụ: khung [jQuery](http://jquery.com) định nghĩa một hàm tên là `$`. Thư viện [Lodash](http://lodash.com/) có hàm cốt lõi tên là `_`.

Đây là những trường hợp ngoại lệ. Nói chung tên hàm phải ngắn gọn và mang tính mô tả.
```

## Hàm == Bình luận
## Hàm == Chú thích

Các hàm phải ngắn gọn và thực hiện chính xác một việc. Nếu thứ đó lớn, có lẽ nên chia hàm thành một vài hàm nhỏ hơn. Đôi khi việc tuân theo quy tắc này có thể không dễ dàng nhưng đó chắc chắn là một điều tốt.

Một chức năng riêng biệt không chỉ dễ kiểm tra và gỡ lỗi hơn -- sự tồn tại của nó là một nhận xét tuyệt vời!
Một chức năng riêng biệt không chỉ dễ kiểm tra và gỡ lỗi hơn -- là một chú thích tuyệt vời!

Ví dụ: so sánh hai hàm `showPrimes(n)` bên dưới. Mỗi cái xuất ra [số nguyên tố](https://en.wikipedia.org/wiki/Prime_number) tối đa `n`.

Expand Down Expand Up @@ -473,16 +473,16 @@ function name(parameters, delimited, by, comma) {

- Các giá trị được truyền vào hàm dưới dạng tham số sẽ được sao chép vào các biến cục bộ của hàm đó.
- Một hàm có thể truy cập các biến ngoài. Nhưng nó chỉ hoạt động từ trong ra ngoài. Mã bên ngoài hàm không thấy các biến cục bộ của nó.
- Hàm có thể trả về một giá trị. Nếu không, thì kết quả của nó là `không xác định`.
- Hàm có thể trả về một giá trị. Nếu không, thì kết quả của nó là `undefined`.

Để làm cho mã rõ ràng và dễ hiểu, bạn nên sử dụng chủ yếu các biến và tham số cục bộ trong hàm, không nên sử dụng các biến bên ngoài.
Để làm cho mã rõ ràng và dễ hiểu, bạn nên sử dụng chủ yếu các biến cục bộ và tham số trong hàm, không nên sử dụng các biến bên ngoài.

Việc hiểu một hàm nhận tham số, làm việc với chúng trả về kết quả luôn dễ dàng hơn so với hàm không nhận tham số nhưng sửa đổi các biến bên ngoài như một tác dụng phụ.
Việc hiểu một hàm nhận các tham số, sử dụng chúng rồi trả về một kết quả, luôn dễ hiểu hơn một hàm không nhận tham số nào, nhưng lại thay đổi giá trị của các biến ngoài, như một tác dụng phụ.

Đặt tên cho hàm:

- Tên phải mô tả rõ ràng chức năng của nó. Khi chúng ta thấy một lệnh gọi hàm trong mã, một cái tên hay sẽ ngay lập tức cho chúng ta hiểu nó làm gì và trả về.
- Hàm là một hành động nên tên hàm thường bằng lời nói.
- Tồn tại nhiều tiền tố hàm phổ biến như `create…`, `show…`, `get…`, `check…`, v.v. Sử dụng chúng để gợi ý chức năng của một chức năng.
- Tên phải mô tả rõ ràng chức năng của nó. Khi chúng ta thấy một lệnh gọi hàm trong mã, một cái tên hay sẽ ngay lập tức giúp chúng ta hiểu nó làm gì và trả về.
- Hàm là một hành động nên tên hàm thường là động từ.
- Tồn tại nhiều tiền tố hàm phổ biến như `create…`, `show…`, `get…`, `check…`, v.v. Sử dụng chúng để gợi ý chức năng của một hàm.

Hàm là khối xây dựng chính của tập lệnh. Hiện tại chúng ta đã đề cập đến những điều cơ bản, vì vậy chúng ta thực sự có thể bắt đầu tạo và sử dụng chúng. Nhưng đó mới chỉ là sự khởi đầu. Chúng ta sẽ còn quay lại chúng nhiều lần, đi sâu hơn vào các tính năng nâng cao của chúng.