diff --git a/1-js/05-data-types/03-string/1-ucfirst/solution.md b/1-js/05-data-types/03-string/1-ucfirst/solution.md
index f7a332d0d..5ab8c7f2c 100644
--- a/1-js/05-data-types/03-string/1-ucfirst/solution.md
+++ b/1-js/05-data-types/03-string/1-ucfirst/solution.md
@@ -1,19 +1,19 @@
-We can't "replace" the first character, because strings in JavaScript are immutable.
+Chúng ta không thể "thay thế" ký tự đầu tiên, bởi vì các chuỗi trong JavaScript là bất biến.
-But we can make a new string based on the existing one, with the uppercased first character:
+Nhưng chúng ta có thể tạo một chuỗi mới dựa trên chuỗi hiện có, với ký tự đầu tiên được viết hoa:
```js
let newStr = str[0].toUpperCase() + str.slice(1);
```
-There's a small problem though. If `str` is empty, then `str[0]` is `undefined`, and as `undefined` doesn't have the `toUpperCase()` method, we'll get an error.
+Có một vấn đề nhỏ mặc dù. Nếu `str` trống, thì `str[0]` là `undefined` và vì `undefined` không có phương thức `toUpperCase()` nên chúng ta sẽ gặp lỗi.
-There are two variants here:
+Có hai biến thể ở đây:
-1. Use `str.charAt(0)`, as it always returns a string (maybe empty).
-2. Add a test for an empty string.
+1. Sử dụng `str.charAt(0)`, vì nó luôn trả về một chuỗi (có thể trống).
+2. Thêm kiểm tra cho chuỗi trống.
-Here's the 2nd variant:
+Đây là biến thể thứ 2:
```js run demo
function ucFirst(str) {
diff --git a/1-js/05-data-types/03-string/1-ucfirst/task.md b/1-js/05-data-types/03-string/1-ucfirst/task.md
index ed8a1e6a7..2ef43243f 100644
--- a/1-js/05-data-types/03-string/1-ucfirst/task.md
+++ b/1-js/05-data-types/03-string/1-ucfirst/task.md
@@ -2,9 +2,9 @@ importance: 5
---
-# Uppercase the first character
+# Chữ hoa ký tự đầu tiên
-Write a function `ucFirst(str)` that returns the string `str` with the uppercased first character, for instance:
+Ví dụ, viết hàm `ucFirst(str)` trả về chuỗi `str` với ký tự đầu tiên được viết hoa:
```js
ucFirst("john") == "John";
diff --git a/1-js/05-data-types/03-string/2-check-spam/solution.md b/1-js/05-data-types/03-string/2-check-spam/solution.md
index de8dde57d..fb20c49c9 100644
--- a/1-js/05-data-types/03-string/2-check-spam/solution.md
+++ b/1-js/05-data-types/03-string/2-check-spam/solution.md
@@ -1,4 +1,4 @@
-To make the search case-insensitive, let's bring the string to lower case and then search:
+Để làm cho tìm kiếm không phân biệt chữ hoa chữ thường, hãy chuyển chuỗi thành chữ thường và sau đó tìm kiếm:
```js run demo
function checkSpam(str) {
diff --git a/1-js/05-data-types/03-string/2-check-spam/task.md b/1-js/05-data-types/03-string/2-check-spam/task.md
index 98b5dd8a0..d2765d7ee 100644
--- a/1-js/05-data-types/03-string/2-check-spam/task.md
+++ b/1-js/05-data-types/03-string/2-check-spam/task.md
@@ -2,11 +2,11 @@ importance: 5
---
-# Check for spam
+# Kiểm tra spam
-Write a function `checkSpam(str)` that returns `true` if `str` contains 'viagra' or 'XXX', otherwise `false`.
+Viết hàm `checkSpam(str)` trả về `true` nếu `str` chứa 'viagra' hoặc 'XXX', nếu không thì `false`.
-The function must be case-insensitive:
+Hàm phải phân biệt chữ hoa chữ thường:
```js
checkSpam('buy ViAgRA now') == true
diff --git a/1-js/05-data-types/03-string/3-truncate/solution.md b/1-js/05-data-types/03-string/3-truncate/solution.md
index d51672ae6..e54fab7bf 100644
--- a/1-js/05-data-types/03-string/3-truncate/solution.md
+++ b/1-js/05-data-types/03-string/3-truncate/solution.md
@@ -1,6 +1,6 @@
-The maximal length must be `maxlength`, so we need to cut it a little shorter, to give space for the ellipsis.
+Độ dài tối đa phải là `maxlength`, vì vậy chúng ta cần cắt nó ngắn hơn một chút để tạo khoảng trống cho dấu chấm lửng.
-Note that there is actually a single Unicode character for an ellipsis. That's not three dots.
+Lưu ý rằng thực tế có một ký tự Unicode duy nhất cho dấu chấm lửng. Đó không phải là ba chấm.
```js run demo
function truncate(str, maxlength) {
diff --git a/1-js/05-data-types/03-string/3-truncate/task.md b/1-js/05-data-types/03-string/3-truncate/task.md
index 6382029f4..4f6e78367 100644
--- a/1-js/05-data-types/03-string/3-truncate/task.md
+++ b/1-js/05-data-types/03-string/3-truncate/task.md
@@ -2,13 +2,13 @@ importance: 5
---
-# Truncate the text
+# Cắt bớt văn bản
-Create a function `truncate(str, maxlength)` that checks the length of the `str` and, if it exceeds `maxlength` -- replaces the end of `str` with the ellipsis character `"…"`, to make its length equal to `maxlength`.
+Tạo một hàm `truncate(str, maxlength)` để kiểm tra độ dài của `str` và, nếu nó vượt quá `maxlength` -- thay thế phần cuối của `str` bằng ký tự dấu chấm lửng `"…"`, để tạo chiều dài bằng `maxlength`.
-The result of the function should be the truncated (if needed) string.
+Kết quả của hàm phải là chuỗi bị cắt ngắn (nếu cần).
-For instance:
+Ví dụ:
```js
truncate("What I'd like to tell on this topic is:", 20) = "What I'd like to te…"
diff --git a/1-js/05-data-types/03-string/4-extract-currency/task.md b/1-js/05-data-types/03-string/4-extract-currency/task.md
index feb16e642..0f397fe5f 100644
--- a/1-js/05-data-types/03-string/4-extract-currency/task.md
+++ b/1-js/05-data-types/03-string/4-extract-currency/task.md
@@ -2,13 +2,13 @@ importance: 4
---
-# Extract the money
+# Trích xuất tiền
-We have a cost in the form `"$120"`. That is: the dollar sign goes first, and then the number.
+Chúng ta có chi phí ở dạng `"$120"`. Đó là: ký hiệu đô la đi trước, sau đó là số.
-Create a function `extractCurrencyValue(str)` that would extract the numeric value from such string and return it.
+Tạo một hàm `extractCurrencyValue(str)` sẽ trích xuất giá trị số từ chuỗi đó và trả về giá trị đó.
-The example:
+Ví dụ:
```js
alert( extractCurrencyValue('$120') === 120 ); // true
diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md
index d5bda9690..c824f12ac 100644
--- a/1-js/05-data-types/03-string/article.md
+++ b/1-js/05-data-types/03-string/article.md
@@ -1,23 +1,23 @@
-# Strings
+# Chuỗi
-In JavaScript, the textual data is stored as strings. There is no separate type for a single character.
+Trong JavaScript, dữ liệu văn bản được lưu trữ dưới dạng chuỗi. Không có loại riêng cho một ký tự.
-The internal format for strings is always [UTF-16](https://en.wikipedia.org/wiki/UTF-16), it is not tied to the page encoding.
+Định dạng bên trong của chuỗi luôn là [UTF-16](https://en.wikipedia.org/wiki/UTF-16), định dạng này không bị ràng buộc với mã hóa trang.
-## Quotes
+## Dấu ngoặc kép
-Let's recall the kinds of quotes.
+Hãy nhớ lại các loại dấu ngoặc kép.
-Strings can be enclosed within either single quotes, double quotes or backticks:
+Các chuỗi có thể được đặt trong dấu ngoặc đơn, dấu ngoặc kép hoặc dấu backticks:
```js
-let single = 'single-quoted';
-let double = "double-quoted";
+let single = 'dấu ngoặc đơn';
+let double = "dấu ngoặc kép";
-let backticks = `backticks`;
+let backticks = `dấu backticks`;
```
-Single and double quotes are essentially the same. Backticks, however, allow us to embed any expression into the string, by wrapping it in `${…}`:
+Dấu ngoặc đơn và dấu ngoặc kép về cơ bản là giống nhau. Tuy nhiên, Backticks cho phép chúng ta nhúng bất kỳ biểu thức nào vào chuỗi, bằng cách gói nó trong `${…}`:
```js run
function sum(a, b) {
@@ -27,7 +27,7 @@ function sum(a, b) {
alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3.
```
-Another advantage of using backticks is that they allow a string to span multiple lines:
+Một ưu điểm khác của việc sử dụng backticks là chúng cho phép một chuỗi trải dài trên nhiều dòng:
```js run
let guestList = `Guests:
@@ -36,212 +36,200 @@ let guestList = `Guests:
* Mary
`;
-alert(guestList); // a list of guests, multiple lines
+alert(guestList); // một danh sách khách, nhiều dòng
```
-Looks natural, right? But single or double quotes do not work this way.
+Trông tự nhiên nhỉ? Nhưng dấu ngoặc đơn hoặc dấu ngoặc kép không hoạt động theo cách này.
-If we use them and try to use multiple lines, there'll be an error:
+Nếu chúng ta sử dụng chúng và cố gắng sử dụng nhiều dòng, sẽ có lỗi:
```js run
let guestList = "Guests: // Error: Unexpected token ILLEGAL
* John";
```
-Single and double quotes come from ancient times of language creation when the need for multiline strings was not taken into account. Backticks appeared much later and thus are more versatile.
+Dấu ngoặc đơn và dấu ngoặc kép xuất hiện từ thời cổ đại khi tạo ngôn ngữ, khi nhu cầu về chuỗi nhiều dòng không được tính đến. Backticks xuất hiện muộn hơn nhiều và do đó linh hoạt hơn.
-Backticks also allow us to specify a "template function" before the first backtick. The syntax is: func`string`. The function `func` is called automatically, receives the string and embedded expressions and can process them. This is called "tagged templates". This feature makes it easier to implement custom templating, but is rarely used in practice. You can read more about it in the [manual](mdn:/JavaScript/Reference/Template_literals#Tagged_templates).
+Backticks cũng cho phép chúng ta chỉ định một "hàm mẫu" trước backtick đầu tiên. Cú pháp là: func`string`. Hàm `func` được gọi tự động, nhận chuỗi và các biểu thức được nhúng và có thể xử lý chúng. Tính năng này được gọi là "mẫu được gắn thẻ", nó hiếm khi được nhìn thấy, nhưng bạn có thể đọc về nó trong MDN: [Template literals](mdn:/JavaScript/Reference/Template_literals#Tagged_templates).
-## Special characters
+## Ký tự đặc biệt
-It is still possible to create multiline strings with single and double quotes by using a so-called "newline character", written as `\n`, which denotes a line break:
+Vẫn có thể tạo chuỗi nhiều dòng với dấu nháy đơn và kép bằng cách sử dụng cái gọi là "ký tự dòng mới", được viết là `\n`, biểu thị ngắt dòng:
```js run
let guestList = "Guests:\n * John\n * Pete\n * Mary";
-alert(guestList); // a multiline list of guests
+alert(guestList); // một danh sách khách nhiều dòng, giống như trên
```
-For example, these two lines are equal, just written differently:
+Như một ví dụ đơn giản hơn, hai dòng này bằng nhau, chỉ được viết khác nhau:
```js run
-let str1 = "Hello\nWorld"; // two lines using a "newline symbol"
+let str1 = "Hello\nWorld"; // hai dòng sử dụng một "ký tự dòng mới"
-// two lines using a normal newline and backticks
+// hai dòng sử dụng một dòng mới bình thường và backticks
let str2 = `Hello
World`;
alert(str1 == str2); // true
```
-There are other, less common "special" characters.
+Có các ký tự đặc biệt khác, ít phổ biến hơn:
-Here's the full list:
-
-| Character | Description |
-|-----------|-------------|
-|`\n`|New line|
-|`\r`|Carriage return: not used alone. Windows text files use a combination of two characters `\r\n` to represent a line break. |
-|`\'`, `\"`|Quotes|
-|`\\`|Backslash|
+| Nhân vật | Mô tả |
+|--------|-------------|
+|`\n`|Dòng mới|
+|`\r`|Trong các tệp văn bản Windows, sự kết hợp của hai ký tự `\r\n` biểu thị một ngắt mới, trong khi trên hệ điều hành không phải Windows, nó chỉ là `\n`. Đó là vì lý do lịch sử, hầu hết các phần mềm Windows cũng hiểu `\n`. |
+|`\'`, `\"`, \\`|Trích dẫn|
+|`\\`|Dấu gạch chéo ngược|
|`\t`|Tab|
-|`\b`, `\f`, `\v`| Backspace, Form Feed, Vertical Tab -- kept for compatibility, not used nowadays. |
-|`\xXX`|Unicode character with the given hexadecimal Unicode `XX`, e.g. `'\x7A'` is the same as `'z'`.|
-|`\uXXXX`|A Unicode symbol with the hex code `XXXX` in UTF-16 encoding, for instance `\u00A9` -- is a Unicode for the copyright symbol `©`. It must be exactly 4 hex digits. |
-|`\u{X…XXXXXX}` (1 to 6 hex characters)|A Unicode symbol with the given UTF-32 encoding. Some rare characters are encoded with two Unicode symbols, taking 4 bytes. This way we can insert long codes. |
+|`\b`, `\f`, `\v`| Backspace, Form Feed, Tab Dọc -- nhắc đến cho đầy đủ, có từ xưa, nay không dùng (có thể quên ngay)). |
+
+Như bạn có thể thấy, tất cả các ký tự đặc biệt đều bắt đầu bằng ký tự gạch chéo ngược `\`. Nó còn được gọi là "ký tự thoát".
-Examples with Unicode:
+Bởi vì nó rất đặc biệt, nên nếu chúng ta cần hiển thị dấu gạch chéo ngược `\` thực sự trong chuỗi, chúng ta cần nhân đôi nó:
```js run
-alert( "\u00A9" ); // ©
-alert( "\u{20331}" ); // 佫, a rare Chinese hieroglyph (long Unicode)
-alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long Unicode)
+alert( `Dấu gạch chéo ngược: \\` ); // Dấu gạch chéo ngược: \
```
-All special characters start with a backslash character `\`. It is also called an "escape character".
+Cái gọi là trích dẫn "thoát" `\'`, `\"`, \\` được sử dụng để chèn một trích dẫn vào cùng một chuỗi được trích dẫn.
-We might also use it if we wanted to insert a quote into the string.
-
-For instance:
+Ví dụ:
```js run
alert( 'I*!*\'*/!*m the Walrus!' ); // *!*I'm*/!* the Walrus!
```
-As you can see, we have to prepend the inner quote by the backslash `\'`, because otherwise it would indicate the string end.
+Như bạn có thể thấy, chúng ta phải thêm vào trước trích dẫn bên trong bằng dấu gạch chéo ngược `\'`, vì nếu không nó sẽ cho biết kết thúc chuỗi.
-Of course, only the quotes that are the same as the enclosing ones need to be escaped. So, as a more elegant solution, we could switch to double quotes or backticks instead:
+Tất nhiên, chỉ những trích dẫn giống với những trích dẫn kèm theo mới cần được thoát. Vì vậy, như một giải pháp tao nhã hơn, thay vào đó, chúng ta có thể chuyển sang dấu ngoặc kép hoặc dấu nháy ngược:
```js run
-alert( `I'm the Walrus!` ); // I'm the Walrus!
+alert( "I'm the Walrus!" ); // I'm the Walrus!
```
-Note that the backslash `\` serves for the correct reading of the string by JavaScript, then disappears. The in-memory string has no `\`. You can clearly see that in `alert` from the examples above.
+Bên cạnh những ký tự đặc biệt này, còn có một ký hiệu đặc biệt cho mã Unicode `\u…`, ký hiệu này hiếm khi được sử dụng và được trình bày trong chương tùy chọn về [Unicode](info:unicode).
-But what if we need to show an actual backslash `\` within the string?
+## Chiều dài chuỗi
-That's possible, but we need to double it like `\\`:
-
-```js run
-alert( `The backslash: \\` ); // The backslash: \
-```
-
-## String length
-
-The `length` property has the string length:
+Thuộc tính `length` có độ dài chuỗi:
```js run
alert( `My\n`.length ); // 3
```
-Note that `\n` is a single "special" character, so the length is indeed `3`.
+Lưu ý rằng `\n` là một ký tự "đặc biệt", vì vậy độ dài thực sự là `3`.
-```warn header="`length` is a property"
-People with a background in some other languages sometimes mistype by calling `str.length()` instead of just `str.length`. That doesn't work.
+```warn header="`length` là thuộc tính"
+Những người có kiến thức cơ bản về một số ngôn ngữ khác đôi khi gõ nhầm bằng cách gọi `str.length()` thay vì chỉ `str.length`. Điều đó không hiệu quả.
-Please note that `str.length` is a numeric property, not a function. There is no need to add parenthesis after it.
+Hãy lưu ý rằng `str.length` là thuộc tính số, không phải hàm. Không cần thêm dấu ngoặc đơn sau nó. Không phải `.length()`, mà là `.length`.
```
-## Accessing characters
+## Truy cập ký tự
-To get a character at position `pos`, use square brackets `[pos]` or call the method [str.charAt(pos)](mdn:js/String/charAt). The first character starts from the zero position:
+Để lấy một ký tự ở vị trí `pos`, hãy sử dụng dấu ngoặc vuông `[pos]` hoặc gọi phương thức [str.at(pos)](mdn:js/String/at). Ký tự đầu tiên bắt đầu từ vị trí số 0:
```js run
-let str = `Hello`;
+let str = `Xin chào`;
-// the first character
-alert( str[0] ); // H
-alert( str.charAt(0) ); // H
+// ký tự đầu tiên
+alert( str[0] ); // X
+alert( str.at(0) ); // X
-// the last character
+// ký tự cuối cùng
alert( str[str.length - 1] ); // o
+alert( str.at(-1) );
```
-The square brackets are a modern way of getting a character, while `charAt` exists mostly for historical reasons.
+Như bạn có thể thấy, phương thức `.at(pos)` có lợi ích là cho phép vị trí âm. Nếu `pos` là số âm, thì nó được tính từ cuối chuỗi.
+
+Vì vậy, `.at(-1)` có nghĩa là ký tự cuối cùng và `.at(-2)` là ký tự trước nó, v.v.
-The only difference between them is that if no character is found, `[]` returns `undefined`, and `charAt` returns an empty string:
+Ví dụ: dấu ngoặc vuông luôn trả về `undefined` cho các chỉ mục phủ định:
```js run
-let str = `Hello`;
+let str = `Xin chào`;
-alert( str[1000] ); // undefined
-alert( str.charAt(1000) ); // '' (an empty string)
+alert( str[-2] ); // undefined
+alert( str.at(-2) ); // 'à'
```
-We can also iterate over characters using `for..of`:
+Chúng ta cũng có thể lặp lại các ký tự bằng cách sử dụng `for..of`:
```js run
-for (let char of "Hello") {
- alert(char); // H,e,l,l,o (char becomes "H", then "e", then "l" etc)
+for (let char of "Xin chào") {
+ alert(char); // X,i,n, ,c,h,à,o (char trở thành "X", rồi "i", rồi "n", v.v.)
}
```
-## Strings are immutable
+## Chuỗi là bất biến
-Strings can't be changed in JavaScript. It is impossible to change a character.
+Không thể thay đổi chuỗi trong JavaScript. Không thể thay đổi một nhân vật.
-Let's try it to show that it doesn't work:
+Hãy thử để chứng minh rằng nó không hoạt động:
```js run
let str = 'Hi';
-str[0] = 'h'; // error
-alert( str[0] ); // doesn't work
+str[0] = 'h'; // lỗi
+alert( str[0] ); // không hoạt động
```
-The usual workaround is to create a whole new string and assign it to `str` instead of the old one.
+Cách giải quyết thông thường là tạo một chuỗi hoàn toàn mới và gán nó cho `str` thay vì chuỗi cũ.
-For instance:
+Ví dụ:
```js run
let str = 'Hi';
-str = 'h' + str[1]; // replace the string
+str = 'h' + str[1]; // thay thế chuỗi
alert( str ); // hi
```
-In the following sections we'll see more examples of this.
+Trong các phần sau chúng ta sẽ thấy nhiều ví dụ hơn về điều này.
-## Changing the case
+## Thay đổi kiểu chữ
-Methods [toLowerCase()](mdn:js/String/toLowerCase) and [toUpperCase()](mdn:js/String/toUpperCase) change the case:
+Các phương thức [toLowerCase()](mdn:js/String/toLowerCase) và [toUpperCase()](mdn:js/String/toUpperCase) thay đổi kiểu chữ:
```js run
-alert( 'Interface'.toUpperCase() ); // INTERFACE
-alert( 'Interface'.toLowerCase() ); // interface
+ alert( 'Interface'.toUpperCase() ); // INTERFACE
+alert( 'Interface'.toLowerCase() ); // Interface
```
-Or, if we want a single character lowercased:
+Hoặc, nếu chúng ta muốn một ký tự được viết thường:
-```js
+```js run
alert( 'Interface'[0].toLowerCase() ); // 'i'
```
-## Searching for a substring
+## Tìm kiếm một chuỗi con
-There are multiple ways to look for a substring within a string.
+Có nhiều cách để tìm kiếm một chuỗi con trong một chuỗi.
### str.indexOf
-The first method is [str.indexOf(substr, pos)](mdn:js/String/indexOf).
+Phương thức đầu tiên là [str.indexOf(substr, pos)](mdn:js/String/indexOf).
-It looks for the `substr` in `str`, starting from the given position `pos`, and returns the position where the match was found or `-1` if nothing can be found.
+Nó tìm kiếm `substr` trong `str`, bắt đầu từ vị trí đã cho `pos` và trả về vị trí tìm thấy kết quả khớp hoặc `-1` nếu không tìm thấy gì.
-For instance:
+Ví dụ:
```js run
let str = 'Widget with id';
-alert( str.indexOf('Widget') ); // 0, because 'Widget' is found at the beginning
-alert( str.indexOf('widget') ); // -1, not found, the search is case-sensitive
+alert( str.indexOf('Widget') ); // 0, bởi vì 'Widget' được tìm thấy ngay từ đầu
+alert( str.indexOf('widget') ); // -1, không tìm thấy, tìm kiếm phân biệt chữ hoa chữ thường
-alert( str.indexOf("id") ); // 1, "id" is found at the position 1 (..idget with id)
+alert( str.indexOf("id") ); // 1, "id" được tìm thấy ở vị trí 1 (..idget với id)
```
-The optional second parameter allows us to start searching from a given position.
+Tham số thứ hai tùy chọn cho phép chúng ta bắt đầu tìm kiếm từ một vị trí nhất định.
-For instance, the first occurrence of `"id"` is at position `1`. To look for the next occurrence, let's start the search from position `2`:
+Chẳng hạn, lần xuất hiện đầu tiên của `"id"` là ở vị trí `1`. Để tìm kiếm lần xuất hiện tiếp theo, hãy bắt đầu tìm kiếm từ vị trí `2`:
```js run
let str = 'Widget with id';
@@ -249,24 +237,24 @@ let str = 'Widget with id';
alert( str.indexOf('id', 2) ) // 12
```
-If we're interested in all occurrences, we can run `indexOf` in a loop. Every new call is made with the position after the previous match:
+Nếu chúng ta quan tâm đến tất cả các lần xuất hiện, chúng tôi có thể chạy `indexOf` trong một vòng lặp. Mỗi cuộc gọi mới được thực hiện với vị trí sau sự trùng khớp trước đó:
```js run
let str = 'As sly as a fox, as strong as an ox';
-let target = 'as'; // let's look for it
+let target = 'as'; // hãy tìm kiếm nó
let pos = 0;
while (true) {
let foundPos = str.indexOf(target, pos);
if (foundPos == -1) break;
- alert( `Found at ${foundPos}` );
- pos = foundPos + 1; // continue the search from the next position
+ alert( `Đã tìm thấy tại ${foundPos}` );
+ pos = foundPos + 1; // tiếp tục tìm kiếm từ vị trí tiếp theo
}
```
-The same algorithm can be layed out shorter:
+Thuật toán tương tự có thể được trình bày ngắn hơn:
```js run
let str = "As sly as a fox, as strong as an ox";
@@ -281,24 +269,24 @@ while ((pos = str.indexOf(target, pos + 1)) != -1) {
```
```smart header="`str.lastIndexOf(substr, position)`"
-There is also a similar method [str.lastIndexOf(substr, position)](mdn:js/String/lastIndexOf) that searches from the end of a string to its beginning.
+Ngoài ra còn có một phương thức tương tự [str.lastIndexOf(substr, position)](mdn:js/String/lastIndexOf) tìm kiếm từ cuối chuỗi đến đầu chuỗi.
-It would list the occurrences in the reverse order.
+Nó sẽ liệt kê các lần xuất hiện theo thứ tự ngược lại.
```
-There is a slight inconvenience with `indexOf` in the `if` test. We can't put it in the `if` like this:
+Có một chút bất tiện với `indexOf` trong bài kiểm tra `if`. Chúng ta không thể đặt nó trong `if` như thế này:
```js run
let str = "Widget with id";
if (str.indexOf("Widget")) {
- alert("We found it"); // doesn't work!
+ alert("Chúng ta đã tìm thấy nó"); // không hoạt động!
}
```
-The `alert` in the example above doesn't show because `str.indexOf("Widget")` returns `0` (meaning that it found the match at the starting position). Right, but `if` considers `0` to be `false`.
+`alert` trong ví dụ trên không hiển thị vì `str.indexOf("Widget")` trả về `0` (có nghĩa là nó tìm thấy kết quả khớp ở vị trí bắt đầu). Đúng, nhưng `if` coi `0` là `false`.
-So, we should actually check for `-1`, like this:
+Vì vậy, chúng ta thực sự nên kiểm tra `-1`, như sau:
```js run
let str = "Widget with id";
@@ -306,54 +294,15 @@ let str = "Widget with id";
*!*
if (str.indexOf("Widget") != -1) {
*/!*
- alert("We found it"); // works now!
+ alert("Chúng ta đã tìm thấy nó"); // bây giờ hoạt động!
}
```
-#### The bitwise NOT trick
-
-One of the old tricks used here is the [bitwise NOT](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT) `~` operator. It converts the number to a 32-bit integer (removes the decimal part if exists) and then reverses all bits in its binary representation.
-
-In practice, that means a simple thing: for 32-bit integers `~n` equals `-(n+1)`.
-
-For instance:
-
-```js run
-alert( ~2 ); // -3, the same as -(2+1)
-alert( ~1 ); // -2, the same as -(1+1)
-alert( ~0 ); // -1, the same as -(0+1)
-*!*
-alert( ~-1 ); // 0, the same as -(-1+1)
-*/!*
-```
-
-As we can see, `~n` is zero only if `n == -1` (that's for any 32-bit signed integer `n`).
-
-So, the test `if ( ~str.indexOf("...") )` is truthy only if the result of `indexOf` is not `-1`. In other words, when there is a match.
-
-People use it to shorten `indexOf` checks:
-
-```js run
-let str = "Widget";
-
-if (~str.indexOf("Widget")) {
- alert( 'Found it!' ); // works
-}
-```
-
-It is usually not recommended to use language features in a non-obvious way, but this particular trick is widely used in old code, so we should understand it.
-
-Just remember: `if (~str.indexOf(...))` reads as "if found".
-
-To be precise though, as big numbers are truncated to 32 bits by `~` operator, there exist other numbers that give `0`, the smallest is `~4294967295=0`. That makes such check correct only if a string is not that long.
-
-Right now we can see this trick only in the old code, as modern JavaScript provides `.includes` method (see below).
-
### includes, startsWith, endsWith
-The more modern method [str.includes(substr, pos)](mdn:js/String/includes) returns `true/false` depending on whether `str` contains `substr` within.
+Phương thức hiện đại hơn [str.includes(substr, pos)](mdn:js/String/includes) trả về `true/false` tùy thuộc vào việc `str` có chứa `substr` bên trong hay không.
-It's the right choice if we need to test for the match, but don't need its position:
+Đó là lựa chọn phù hợp nếu chúng ta cần kiểm tra sự trùng khớp, nhưng không cần vị trí của nó:
```js run
alert( "Widget with id".includes("Widget") ); // true
@@ -361,152 +310,150 @@ alert( "Widget with id".includes("Widget") ); // true
alert( "Hello".includes("Bye") ); // false
```
-The optional second argument of `str.includes` is the position to start searching from:
+Đối số thứ hai tùy chọn của `str.includes` là vị trí để bắt đầu tìm kiếm từ:
```js run
alert( "Widget".includes("id") ); // true
-alert( "Widget".includes("id", 3) ); // false, from position 3 there is no "id"
+alert( "Widget".includes("id", 3) ); // false, từ vị trí 3 không có "id"
```
-The methods [str.startsWith](mdn:js/String/startsWith) and [str.endsWith](mdn:js/String/endsWith) do exactly what they say:
+Các phương thức [str.startsWith](mdn:js/String/startsWith) và [str.endsWith](mdn:js/String/endsWith) thực hiện chính xác những gì chúng nói:
```js run
-alert( "Widget".startsWith("Wid") ); // true, "Widget" starts with "Wid"
-alert( "Widget".endsWith("get") ); // true, "Widget" ends with "get"
+alert( "*!*Wid*/!*get".startsWith("Wid") ); // true, "Widget" bắt đầu bằng "Wid"
+alert( "Wid*!*get*/!*".endsWith("get") ); // true, "Widget" kết thúc bằng "get"
```
-## Getting a substring
+## Lấy một chuỗi con
-There are 3 methods in JavaScript to get a substring: `substring`, `substr` and `slice`.
+Có 3 phương thức trong JavaScript để lấy chuỗi con: `substring`, `substr` và `slice`.
`str.slice(start [, end])`
-: Returns the part of the string from `start` to (but not including) `end`.
+: Trả về một phần của chuỗi từ `start` đến (nhưng không bao gồm) `end`.
- For instance:
+ Ví dụ:
```js run
let str = "stringify";
- alert( str.slice(0, 5) ); // 'strin', the substring from 0 to 5 (not including 5)
- alert( str.slice(0, 1) ); // 's', from 0 to 1, but not including 1, so only character at 0
+ alert( str.slice(0, 5) ); // 'strin', chuỗi con từ 0 đến 5 (không bao gồm 5)
+ alert( str.slice(0, 1) ); // 's', từ 0 đến 1, nhưng không bao gồm 1, vì vậy chỉ ký tự ở 0
```
- If there is no second argument, then `slice` goes till the end of the string:
+ Nếu không có đối số thứ hai, thì `slice` sẽ đi đến cuối chuỗi:
```js run
let str = "st*!*ringify*/!*";
- alert( str.slice(2) ); // 'ringify', from the 2nd position till the end
+ alert( str.slice(2) ); // 'ringify', từ vị trí thứ 2 đến cuối
```
- Negative values for `start/end` are also possible. They mean the position is counted from the string end:
+ Cũng có thể có các giá trị âm cho `start/end`. Chúng có nghĩa là vị trí được tính từ cuối chuỗi:
```js run
let str = "strin*!*gif*/!*y";
- // start at the 4th position from the right, end at the 1st from the right
+ // bắt đầu ở vị trí thứ 4 từ bên phải, kết thúc ở vị trí thứ 1 từ bên phải
alert( str.slice(-4, -1) ); // 'gif'
```
`str.substring(start [, end])`
-: Returns the part of the string *between* `start` and `end`.
+: Trả về một phần của chuỗi *giữa* `start` và `end` (không bao gồm lớn hơn của chúng).
- This is almost the same as `slice`, but it allows `start` to be greater than `end`.
+ Điều này gần giống với `slice`, nhưng nó cho phép `start` lớn hơn `end`.
- For instance:
+ Ví dụ:
```js run
let str = "st*!*ring*/!*ify";
- // these are same for substring
+ // những cái này giống nhau đối với chuỗi con
alert( str.substring(2, 6) ); // "ring"
alert( str.substring(6, 2) ); // "ring"
- // ...but not for slice:
- alert( str.slice(2, 6) ); // "ring" (the same)
- alert( str.slice(6, 2) ); // "" (an empty string)
+ // ...nhưng không phải cho lát cắt:
+ alert( str.slice(2, 6) ); // "ring" (giống nhau)
+ alert( str.slice(6, 2) ); // "" (một chuỗi rỗng)
```
- Negative arguments are (unlike slice) not supported, they are treated as `0`.
+ Các đối số phủ định (không giống như lát cắt) không được hỗ trợ, chúng được coi là `0`.
`str.substr(start [, length])`
-: Returns the part of the string from `start`, with the given `length`.
+: Trả về một phần của chuỗi từ `bắt đầu`, với `độ dài` đã cho.
- In contrast with the previous methods, this one allows us to specify the `length` instead of the ending position:
+ Ngược lại với các phương pháp trước, phương pháp này cho phép chúng ta chỉ định `độ dài` thay vì vị trí kết thúc:
```js run
let str = "st*!*ring*/!*ify";
- alert( str.substr(2, 4) ); // 'ring', from the 2nd position get 4 characters
+ alert( str.substr(2, 4) ); // 'ring', từ vị trí thứ 2 nhận được 4 ký tự
```
- The first argument may be negative, to count from the end:
+ Đối số đầu tiên có thể là số âm, được tính từ cuối:
```js run
let str = "strin*!*gi*/!*fy";
- alert( str.substr(-4, 2) ); // 'gi', from the 4th position get 2 characters
+ alert( str.substr(-4, 2) ); // 'gi', từ vị trí thứ 4 lấy 2 ký tự
```
+ Phương pháp này nằm trong [Phụ lục B](https://tc39.es/ecma262/#sec-string.prototype.substr) của đặc điểm kỹ thuật ngôn ngữ. Điều đó có nghĩa là chỉ các JavaScript engine được lưu trữ trên trình duyệt mới hỗ trợ nó, và nó không được đề nghị sử dụng. Trong thực tế, nó được hỗ trợ ở khắp mọi nơi.
+
+Hãy tóm tắt lại các phương pháp này để tránh nhầm lẫn:
-Let's recap these methods to avoid any confusion:
+| phương pháp | chọn... | âm bản |
+|---|------------|--------|
+| `slice(start, end)` | từ `start` đến `end` (không bao gồm `end`) | cho phép số âm |
+| `substring(start, end)` | giữa `start` và `end` (không bao gồm `end`)| giá trị âm có nghĩa là `0` |
+| `substr(start, length)` | từ `start` lấy các ký tự `length` | cho phép `start` âm |
-| method | selects... | negatives |
-|--------|-----------|-----------|
-| `slice(start, end)` | from `start` to `end` (not including `end`) | allows negatives |
-| `substring(start, end)` | between `start` and `end` | negative values mean `0` |
-| `substr(start, length)` | from `start` get `length` characters | allows negative `start` |
+```smart header="Chọn cái nào?"
+Tất cả chúng có thể làm công việc. Về mặt hình thức, `substr` có một nhược điểm nhỏ: nó không được mô tả trong thông số kỹ thuật JavaScript cốt lõi mà trong Phụ lục B, bao gồm các tính năng chỉ dành cho trình duyệt tồn tại chủ yếu vì lý do lịch sử. Vì vậy, các môi trường không có trình duyệt có thể không hỗ trợ nó. Nhưng trong thực tế, nó hoạt động ở mọi nơi.
-```smart header="Which one to choose?"
-All of them can do the job. Formally, `substr` has a minor drawback: it is described not in the core JavaScript specification, but in Annex B, which covers browser-only features that exist mainly for historical reasons. So, non-browser environments may fail to support it. But in practice it works everywhere.
+Trong số hai biến thể còn lại, `slice` linh hoạt hơn một chút, nó cho phép đối số âm và viết ngắn hơn.
-Of the other two variants, `slice` is a little bit more flexible, it allows negative arguments and shorter to write. So, it's enough to remember solely `slice` of these three methods.
+Vì vậy, để sử dụng thực tế, chỉ cần nhớ `slice` là đủ.
```
-## Comparing strings
+## So sánh chuỗi
-As we know from the chapter , strings are compared character-by-character in alphabetical order.
+Như chúng ta đã biết từ chương , các chuỗi được so sánh theo từng ký tự theo thứ tự bảng chữ cái.
-Although, there are some oddities.
+Mặc dù, có một số điều kỳ lạ.
-1. A lowercase letter is always greater than the uppercase:
+1. Chữ thường luôn lớn hơn chữ hoa:
```js run
alert( 'a' > 'Z' ); // true
```
-2. Letters with diacritical marks are "out of order":
+2. Các chữ cái có dấu phụ là "không theo thứ tự":
```js run
alert( 'Österreich' > 'Zealand' ); // true
```
- This may lead to strange results if we sort these country names. Usually people would expect `Zealand` to come after `Österreich` in the list.
+ Điều này có thể dẫn đến kết quả lạ nếu chúng ta sắp xếp các tên quốc gia này. Thông thường mọi người sẽ mong đợi `Zealand` sẽ đứng sau `Österreich` trong danh sách.
-To understand what happens, let's review the internal representation of strings in JavaScript.
+Để hiểu điều gì sẽ xảy ra, chúng ta nên biết rằng các chuỗi trong Javascript được mã hóa bằng [UTF-16](https://en.wikipedia.org/wiki/UTF-16). Đó là: mỗi ký tự có một mã số tương ứng.
-All strings are encoded using [UTF-16](https://en.wikipedia.org/wiki/UTF-16). That is: each character has a corresponding numeric code. There are special methods that allow to get the character for the code and back.
+Có các phương thức đặc biệt cho phép lấy ký tự cho mã và ngược lại:
`str.codePointAt(pos)`
-: Returns the code for the character at position `pos`:
+: Trả về một số thập phân biểu thị mã cho ký tự ở vị trí `pos`:
```js run
- // different case letters have different codes
- alert( "z".codePointAt(0) ); // 122
+ // các chữ cái viết hoa và viết thường có mã khác nhau
alert( "Z".codePointAt(0) ); // 90
+ alert( "z".codePointAt(0) ); // 122
+ alert( "z".codePointAt(0).toString(16) ); // 7a (nếu chúng ta cần một giá trị thập lục phân)
```
`String.fromCodePoint(code)`
-: Creates a character by its numeric `code`
+: Tạo một ký tự bằng số `code` của nó
```js run
alert( String.fromCodePoint(90) ); // Z
+ alert( String.fromCodePoint(0x5a) ); // Z (chúng ta cũng có thể sử dụng giá trị hex làm đối số)
```
- We can also add Unicode characters by their codes using `\u` followed by the hex code:
-
- ```js run
- // 90 is 5a in hexadecimal system
- alert( '\u005a' ); // Z
- ```
-
-Now let's see the characters with codes `65..220` (the latin alphabet and a little bit extra) by making a string of them:
+Bây giờ, hãy xem các ký tự có mã `65..220` (bảng chữ cái Latinh và thêm một chút) bằng cách tạo một chuỗi gồm chúng:
```js run
let str = '';
@@ -515,165 +462,60 @@ for (let i = 65; i <= 220; i++) {
str += String.fromCodePoint(i);
}
alert( str );
-// ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
-// ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜ
+// Đầu ra:
+// ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}
+// ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜ
```
-See? Capital characters go first, then a few special ones, then lowercase characters, and `Ö` near the end of the output.
+Thấy chưa? Các ký tự viết hoa xuất hiện trước, sau đó là một vài ký tự đặc biệt, sau đó là các ký tự viết thường và `Ö` ở gần cuối đầu ra.
-Now it becomes obvious why `a > Z`.
+Bây giờ thì rõ ràng là tại sao `a > Z`.
-The characters are compared by their numeric code. The greater code means that the character is greater. The code for `a` (97) is greater than the code for `Z` (90).
+Các ký tự được so sánh bằng mã số của chúng. Mã lớn hơn có nghĩa là ký tự lớn hơn. Mã của `a` (97) lớn hơn mã của `Z` (90).
-- All lowercase letters go after uppercase letters because their codes are greater.
-- Some letters like `Ö` stand apart from the main alphabet. Here, it's code is greater than anything from `a` to `z`.
+- Tất cả các chữ thường đi sau các chữ in hoa vì mã của chúng lớn hơn.
+- Một số chữ cái như `Ö` đứng ngoài bảng chữ cái chính. Ở đây, mã của nó lớn hơn bất kỳ thứ gì từ `a` đến `z`.
-### Correct comparisons [#correct-comparisons]
+### So sánh đúng [#true-comparisons]
-The "right" algorithm to do string comparisons is more complex than it may seem, because alphabets are different for different languages.
+Thuật toán "đúng" để thực hiện so sánh chuỗi phức tạp hơn vẻ ngoài của nó, bởi vì các bảng chữ cái khác nhau đối với các ngôn ngữ khác nhau.
-So, the browser needs to know the language to compare.
+Vì vậy, trình duyệt cần biết ngôn ngữ để so sánh.
-Luckily, all modern browsers (IE10- requires the additional library [Intl.js](https://github.com/andyearnshaw/Intl.js/)) support the internationalization standard [ECMA-402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf).
+May mắn thay, các trình duyệt hiện đại hỗ trợ tiêu chuẩn quốc tế hóa [ECMA-402](https://www.ecma-international.org/publications-and-standards/standards/ecma-402/).
-It provides a special method to compare strings in different languages, following their rules.
+Nó cung cấp một phương pháp đặc biệt để so sánh các chuỗi trong các ngôn ngữ khác nhau, tuân theo các quy tắc của chúng.
-The call [str.localeCompare(str2)](mdn:js/String/localeCompare) returns an integer indicating whether `str` is less, equal or greater than `str2` according to the language rules:
+Lệnh gọi [str.localeCompare(str2)](mdn:js/String/localeCompare) trả về một số nguyên cho biết `str` nhỏ hơn, bằng hay lớn hơn `str2` theo quy tắc ngôn ngữ:
-- Returns a negative number if `str` is less than `str2`.
-- Returns a positive number if `str` is greater than `str2`.
-- Returns `0` if they are equivalent.
+- Trả về số âm nếu `str` nhỏ hơn `str2`.
+- Trả về một số dương nếu `str` lớn hơn `str2`.
+- Trả về `0` nếu chúng bằng nhau.
-For instance:
+Ví dụ:
```js run
alert( 'Österreich'.localeCompare('Zealand') ); // -1
```
-This method actually has two additional arguments specified in [the documentation](mdn:js/String/localeCompare), which allows it to specify the language (by default taken from the environment, letter order depends on the language) and setup additional rules like case sensitivity or should `"a"` and `"á"` be treated as the same etc.
-
-## Internals, Unicode
-
-```warn header="Advanced knowledge"
-The section goes deeper into string internals. This knowledge will be useful for you if you plan to deal with emoji, rare mathematical or hieroglyphic characters or other rare symbols.
-
-You can skip the section if you don't plan to support them.
-```
-
-### Surrogate pairs
-
-All frequently used characters have 2-byte codes. Letters in most european languages, numbers, and even most hieroglyphs, have a 2-byte representation.
-
-But 2 bytes only allow 65536 combinations and that's not enough for every possible symbol. So rare symbols are encoded with a pair of 2-byte characters called "a surrogate pair".
-
-The length of such symbols is `2`:
-
-```js run
-alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X
-alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY
-alert( '𩷶'.length ); // 2, a rare Chinese hieroglyph
-```
-
-Note that surrogate pairs did not exist at the time when JavaScript was created, and thus are not correctly processed by the language!
-
-We actually have a single symbol in each of the strings above, but the `length` shows a length of `2`.
-
-`String.fromCodePoint` and `str.codePointAt` are few rare methods that deal with surrogate pairs right. They recently appeared in the language. Before them, there were only [String.fromCharCode](mdn:js/String/fromCharCode) and [str.charCodeAt](mdn:js/String/charCodeAt). These methods are actually the same as `fromCodePoint/codePointAt`, but don't work with surrogate pairs.
-
-Getting a symbol can be tricky, because surrogate pairs are treated as two characters:
-
-```js run
-alert( '𝒳'[0] ); // strange symbols...
-alert( '𝒳'[1] ); // ...pieces of the surrogate pair
-```
-
-Note that pieces of the surrogate pair have no meaning without each other. So the alerts in the example above actually display garbage.
-
-Technically, surrogate pairs are also detectable by their codes: if a character has the code in the interval of `0xd800..0xdbff`, then it is the first part of the surrogate pair. The next character (second part) must have the code in interval `0xdc00..0xdfff`. These intervals are reserved exclusively for surrogate pairs by the standard.
-
-In the case above:
-
-```js run
-// charCodeAt is not surrogate-pair aware, so it gives codes for parts
-
-alert( '𝒳'.charCodeAt(0).toString(16) ); // d835, between 0xd800 and 0xdbff
-alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3, between 0xdc00 and 0xdfff
-```
-
-You will find more ways to deal with surrogate pairs later in the chapter . There are probably special libraries for that too, but nothing famous enough to suggest here.
-
-### Diacritical marks and normalization
-
-In many languages there are symbols that are composed of the base character with a mark above/under it.
-
-For instance, the letter `a` can be the base character for: `àáâäãåā`. Most common "composite" character have their own code in the UTF-16 table. But not all of them, because there are too many possible combinations.
-
-To support arbitrary compositions, UTF-16 allows us to use several Unicode characters: the base character followed by one or many "mark" characters that "decorate" it.
-
-For instance, if we have `S` followed by the special "dot above" character (code `\u0307`), it is shown as Ṡ.
-
-```js run
-alert( 'S\u0307' ); // Ṡ
-```
-
-If we need an additional mark above the letter (or below it) -- no problem, just add the necessary mark character.
-
-For instance, if we append a character "dot below" (code `\u0323`), then we'll have "S with dots above and below": `Ṩ`.
-
-For example:
-
-```js run
-alert( 'S\u0307\u0323' ); // Ṩ
-```
-
-This provides great flexibility, but also an interesting problem: two characters may visually look the same, but be represented with different Unicode compositions.
-
-For instance:
-
-```js run
-let s1 = 'S\u0307\u0323'; // Ṩ, S + dot above + dot below
-let s2 = 'S\u0323\u0307'; // Ṩ, S + dot below + dot above
-
-alert( `s1: ${s1}, s2: ${s2}` );
-
-alert( s1 == s2 ); // false though the characters look identical (?!)
-```
-
-To solve this, there exists a "Unicode normalization" algorithm that brings each string to the single "normal" form.
-
-It is implemented by [str.normalize()](mdn:js/String/normalize).
-
-```js run
-alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true
-```
-
-It's funny that in our situation `normalize()` actually brings together a sequence of 3 characters to one: `\u1e68` (S with two dots).
-
-```js run
-alert( "S\u0307\u0323".normalize().length ); // 1
-
-alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true
-```
-
-In reality, this is not always the case. The reason being that the symbol `Ṩ` is "common enough", so UTF-16 creators included it in the main table and gave it the code.
+Phương thức này thực sự có hai đối số bổ sung được chỉ định trong [tài liệu](mdn:js/String/localeCompare), cho phép phương thức này chỉ định ngôn ngữ (theo mặc định được lấy từ môi trường, thứ tự chữ cái phụ thuộc vào ngôn ngữ) và thiết lập các quy tắc bổ sung như phân biệt chữ hoa chữ thường hoặc nên coi `"a"` và `"á"` như nhau, v.v.
-If you want to learn more about normalization rules and variants -- they are described in the appendix of the Unicode standard: [Unicode Normalization Forms](http://www.unicode.org/reports/tr15/), but for most practical purposes the information from this section is enough.
+## Tóm tắt
-## Summary
+- Có 3 loại trích dẫn. Backticks cho phép một chuỗi mở rộng trên nhiều dòng và nhúng các biểu thức `${…}`.
+- Chúng ta có thể sử dụng các ký tự đặc biệt, chẳng hạn như ngắt dòng `\n`.
+- Để lấy một ký tự, sử dụng: `[]` hay phương thức `at`.
+- Để lấy chuỗi con, dùng: `slice` hoặc `substring`.
+- Để viết thường/viết hoa một chuỗi, sử dụng: `toLowerCase/toUpperCase`.
+- Để tìm một chuỗi con, hãy sử dụng: `indexOf`, hoặc `includes/startsWith/endsWith` để kiểm tra đơn giản.
+- Để so sánh các chuỗi theo ngôn ngữ, hãy sử dụng: `localeCompare`, nếu không thì chúng được so sánh bằng mã ký tự.
-- There are 3 types of quotes. Backticks allow a string to span multiple lines and embed expressions `${…}`.
-- Strings in JavaScript are encoded using UTF-16.
-- We can use special characters like `\n` and insert letters by their Unicode using `\u...`.
-- To get a character, use: `[]`.
-- To get a substring, use: `slice` or `substring`.
-- To lowercase/uppercase a string, use: `toLowerCase/toUpperCase`.
-- To look for a substring, use: `indexOf`, or `includes/startsWith/endsWith` for simple checks.
-- To compare strings according to the language, use: `localeCompare`, otherwise they are compared by character codes.
+Có một số phương pháp hữu ích khác trong chuỗi:
-There are several other helpful methods in strings:
+- `str.trim()` -- xóa khoảng trắng ("trims") khỏi đầu và cuối chuỗi.
+- `str.repeat(n)` -- lặp lại chuỗi `n` lần.
+- ...và nhiều hơn nữa được tìm thấy trong [hướng dẫn sử dụng](mdn:js/String).
-- `str.trim()` -- removes ("trims") spaces from the beginning and end of the string.
-- `str.repeat(n)` -- repeats the string `n` times.
-- ...and more to be found in the [manual](mdn:js/String).
+Các chuỗi cũng có các phương thức để thực hiện tìm kiếm/thay thế bằng các biểu thức thông thường. Nhưng đó là chủ đề lớn nên nó được giải thích trong phần hướng dẫn riêng biệt .
-Strings also have methods for doing search/replace with regular expressions. But that's big topic, so it's explained in a separate tutorial section .
+Ngoài ra, hiện tại, điều quan trọng cần biết là các chuỗi dựa trên mã hóa Unicode và do đó, có vấn đề khi so sánh. Có thêm thông tin về Unicode trong chương .