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ự.

Định dạng bên trong cho chuỗi luôn là UTF-16, nó không bị ràng buộc với code hóa.

Đoạn văn bản

Hãy nhớ lại các loại trích dẫn.

Các chuỗi có thể được đặt trong một dấu ngoặc đơn, dấu ngoặc kép hoặc backticks:

/*
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 single = 'single-quoted';
let double = "double-quoted";

let backticks = `backticks`;

Dấu nhấy đơn và đôi 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ó vào ${…}:

function sum(a, b) {
  return a + b;
}

alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3.

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:

let guestList = `Guests:
 * John
 * Pete
 * Mary
`;

alert(guestList); // a list of guests, multiple lines

Trông thật tự nhiên phải không? Nhưng dấu ngoặc đơn hoặc kép không hoạt động theo cách này.

Nếu chúng ta sử dụng chúng và cố gắng sử dụng nhiều dòng, sẽ có một lỗi:

let guestList = "Guests: // Error: Unexpected token ILLEGAL
  * John";

Các trích dẫn đơn và kép xuất phát từ thời cổ đại của việc tạo ra ngôn ngữ khi nhu cầu về các chuỗi đa 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 cũng cho phép chúng ta chỉ định một hàm mẫu trước khi có backtick. Cú pháp là : func`string`. Hàm funcđược gọi tự động, nhận chuỗi và biểu thức nhúng và có thể xử lý chúng. Đây được gọi là các mẫu được gắn thẻ. Tính năng này giúp dễ dàng thực hiện tạo khuôn mẫu tùy chỉnh, nhưng hiếm khi được sử dụng trong thực tế. Bạn có thể đọc thêm về nó trong hướng dẫn.

Ký tự đặc biệt

Vẫn có thể tạo các chuỗi nhiều dòng với dấu ngoặc đơn và dấu ngoặc kép bằng cách sử dụng cái gọi là ký tự dòng mới của dòng, được viết là \n, biểu thị một ngắt dòng:

let guestList = "Guests:\n * John\n * Pete\n * Mary";

alert(guestList); // a multiline list of guests

Ví dụ, hai dòng này bằng nhau, chỉ được viết khác nhau:

let str1 = "Hello\nWorld"; // two lines using a "newline symbol"

// two lines using a normal newline and backticks
let str2 = `Hello
World`;

alert(str1 == str2); // true

Có những ký tự khác, ít phổ biến hơn.

Đây là danh sách đầy đủ:

Ký tựSự miêu tả
\nDòng mới
\rTrở lại đầu dòng: không được sử dụng một mình. Các tệp văn bản Windows sử dụng kết hợp hai ký tự \r\nđể thể hiện ngắt dòng.
\', \"Đánh dấu cho các Quotes
\\Dấu gạch chéo ngược
\tChuyển hướng
\b, \f,\vBackspace, Form Feed, Tab dọc – được giữ để tương thích, hiện không được sử dụng.
\xXXKý tự Unicode với unicode thập lục phân đã XX, ví dụ như '\x7A'giống như 'z'.
\uXXXXXXXXChẳng hạn \u00A9, một biểu tượng unicode với mã hex trong mã hóa UTF-16 – là một unicode cho biểu tượng bản quyền ©. Nó phải chính xác là 4 chữ số hex.
\u{X…XXXXXX} (1 đến 6 ký tự hex)Một biểu tượng unicode với mã hóa UTF-32 đã cho. Một số ký tự hiếm được mã hóa bằng hai ký hiệu unicode, lấy 4 byte. Bằng cách này chúng ta có thể chèn mã dài.

Ví dụ với unicode:

alert( "\u00A9" ); // ©
alert( "\u{20331}" ); // 佫, a rare Chinese hieroglyph (long unicode)
alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long unicode)

Tất cả các ký tự đặc biệt bắt đầu bằng một ký tự dấu gạch chéo ngược \. Nó cũng được gọi là một ký tự thoát.

Chúng ta cũng có thể sử dụng nó nếu chúng ta muốn chèn một trích dẫn vào chuỗi.

Ví dụ:

alert( 'I\'m the Walrus!' ); // I'm the Walrus!

Như bạn có thể thấy, chúng ta phải thêm vào trích dẫn bên trong bằng dấu gạch chéo ngược \', bởi vì nếu không nó sẽ chỉ ra kết thúc chuỗi.




Tất nhiên, để các trích dẫn giống như các trích dẫn ở trên thì phải kèm theo một ký tự thoát \. Vì vậy, như một giải pháp thanh lịch hơn, chúng ta có thể chuyển sang dấu ngoặc kép hoặc backticks thay thế:

alert( `I'm the Walrus!` ); // I'm the Walrus!

Lưu ý rằng dấu gạch chéo ngược \phục vụ cho việc đọc chính xác chuỗi bằng JavaScript, sau đó biến mất. Chuỗi trong bộ nhớ không có \. Bạn có thể thấy rõ điều đó alerttừ các ví dụ trên.

Nhưng điều gì sẽ xảy ra nếu chúng ta cần hiển thị dấu gạch chéo ngược thực tế \trong chuỗi?

Điều đó có thể, nhưng chúng ta cần tăng gấp đôi như \\sau:

alert( `The backslash: \\` ); // The backslash: \

Chiều dài chuỗi

Các thuộc tính length cho biết độ dài chuỗi:

alert( `My\n`.length ); // 3

Lưu ý rằng đó \nlà một ký tự đặc biệt, vì vậy độ dài thực sự 3.

length là một thuộc tính

Nhiều người biết một số ngôn ngữ khác đôi khi gõ nhầm bằng cách gọistr.length()thay vì chỉ str.length. Điều đó không đúng.

Xin lưu ý rằng đó str.lengthlà một thuộc tính kiểu số, không phải là một hàm. Không cần thêm dấu ngoặc sau nó.

Truy cập ký tự

Để có được một ký tự ở vị trí pos, sử dụng dấu ngoặc vuông [pos]hoặc gọi phương thức str.charAt(pos). Ký tự đầu tiên bắt đầu từ vị trí 0:




let str = `Hello`;

// the first character
alert( str[0] ); // H
alert( str.charAt(0) ); // H

// the last character
alert( str[str.length - 1] ); // o

Dấu ngoặc vuông là một cách hiện đại để có được một ký tự, trong khi charAttồn tại chủ yếu vì lý do lịch sử.

Sự khác biệt duy nhất giữa chúng là nếu không tìm thấy ký tự nào, []trả về undefinedcharAttrả về một chuỗi trống:

let str = `Hello`;

alert( str[1000] ); // undefined
alert( str.charAt(1000) ); // '' (an empty string)

Chúng ta cũng có thể lặp lại các ký tự bằng cách sử dụng for..of:

for (let char of "Hello") {
  alert(char); // H,e,l,l,o (char becomes "H", then "e", then "l" etc)
}

String là không thể sửa được

Chuỗi không thể thay đổi trong JavaScript. Không thể thay đổi một ký tự.

Hãy thử để cho thấy rằng nó không hoạt động:

let str = 'Hi';

str[0] = 'h'; // error
alert( str[0] ); // doesn't work

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 strthay vì chuỗi cũ.

Ví dụ:

let str = 'Hi';

str = 'h' + str[1]; // replace the string

alert( str ); // hi

Trong các phần sau chúng ta sẽ thấy nhiều ví dụ về điều này.

Dùng các case

Các phương thức toLowerCase()toUpperCase():

alert( 'Interface'.toUpperCase() ); // INTERFACE
alert( 'Interface'.toLowerCase() ); // interface

Hoặc, nếu chúng ta muốn một ký tự duy nhất:




alert( 'Interface'[0].toLowerCase() ); // 'i'

Tìm kiếm một chuỗi con

Có nhiều cách để tìm kiếm một chuỗi con trong một chuỗi.

str.indexOf

Phương thức đầu tiên là str.indexOf(substr, pos).

Nó tìm kiếm substrtrong str, bắt đầu từ vị trí đã cho posvà trả về vị trí tìm thấy hoặc -1nếu không tìm thấy gì.

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/
*/

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("id") ); // 1, "id" is found at the position 1 (..idget with id)

Tham số thứ hai tùy chọn cho phép chúng tôi tìm kiếm bắt đầu từ vị trí đã cho.

Ví dụ, sự xuất hiện đầu tiên của "id"là tại vị trí 1. Để tìm kiếm sự xuất hiện tiếp theo, hãy bắt đầu tìm kiếm từ vị trí 2:

let str = 'Widget with id';

alert( str.indexOf('id', 2) ) // 12

Nếu chúng ta quan tâm đến tất cả các lần xuất hiện, chúng ta có thể chạy indexOftrong một vòng lặp. Mỗi khi gọi mới được thực hiện với vị trí trước:

let str = 'As sly as a fox, as strong as an ox';

let target = 'as'; // let's look for it

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
}

Thuật toán tương tự có thể được trình bày ngắn hơn:

let str = "As sly as a fox, as strong as an ox";
let target = "as";

let pos = -1;
while ((pos = str.indexOf(target, pos + 1)) != -1) {
  alert( pos );
}

str.lastIndexOf(substr, position)

Ngoài ra còn có một phương thức tương tự str.lastIndexOf(substr, position) tìm kiếm từ đầu chuỗi đến đầu chuỗi.




Nó sẽ liệt kê các lần xuất hiện theo thứ tự ngược lại.

Có một chút bất tiện indexOftrong bài kiểm tra if. Chúng ta không thể đặt nó ifnhư thế này:

let str = "Widget with id";

if (str.indexOf("Widget")) {
    alert("We found it"); // doesn't work!
}

Trong alertví 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 ifcoi 0là được false.

Vì vậy, chúng ta thực sự nên kiểm tra -1, như thế này:

let str = "Widget with id";

if (str.indexOf("Widget") != -1) {
    alert("We found it"); // works now!
}

Bitwise KHÔNG lừa

Một trong những thủ thuật cũ được sử dụng ở đây là bitwise NOT ~ . Nó chuyển đổi số thành số nguyên 32 bit (loại bỏ phần thập phân nếu tồn tại) và sau đó đảo ngược tất cả các bit trong biểu diễn nhị phân của nó.

Trong thực tế, điều đó có nghĩa là một điều đơn giản: đối với số nguyên 32 bit ~nbằng -(n+1).

Ví dụ:

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)

Như chúng ta có thể thấy, ~nchỉ bằng 0 nếu n == -1(đó là cho bất kỳ số nguyên có chữ ký 32 bit nào n).

Vì vậy, thử nghiệmif ( ~str.indexOf("...") )là đúng nếu kết quả indexOflà không -1. Nói cách khác, khi có khớp.

Mọi người sử dụng nó để rút ngắn indexOfkiểm tra:




let str = "Widget";

if (~str.indexOf("Widget")) {
  alert( 'Found it!' ); // works
}

Thông thường không nên sử dụng các tính năng ngôn ngữ theo cách không rõ ràng, nhưng thủ thuật đặc biệt này được sử dụng rộng rãi trong code cũ, vì vậy chúng ta nên hiểu nó.

Chỉ cần nhớ: if (~str.indexOf(...))đọc như là nếu được tìm thấy.

Nói chính xác, vì các số lớn được rút ngắn thành 32 bit bởi ~toán tử, tồn tại các số khác đưa ra 0, nhỏ nhất là ~4294967295=0. Điều đó làm cho kiểm tra như vậy là chính xác chỉ khi một chuỗi không dài.

Ngay bây giờ chúng ta chỉ có thể thấy thủ thuật này trong code cũ, vì JavaScript hiện đại cung cấp .includesphương thức (xem bên dưới).

includes, startsWith, endsWith

Phương thức hiện đại hơn str.includes(substr, pos) trả về true/falsetùy thuộc vào việc strcó chứa substrbên trong hay không.

Đó là lựa chọn đúng đắn nếu chúng ta cần kiểm tra trận đấu, nhưng không cần vị trí của nó:

alert( "Widget with id".includes("Widget") ); // true

alert( "Hello".includes("Bye") ); // false

Đối số thứ hai tùy chọn str.includeslà vị trí để bắt đầu tìm kiếm từ:

alert( "Widget".includes("id") ); // true
alert( "Widget".includes("id", 3) ); // false, from position 3 there is no "id"

Các phương thức str.startsWith and str.endsWith thực hiện chính xác những gì họ nói:

alert( "Widget".startsWith("Wid") ); // true, "Widget" starts with "Wid"
alert( "Widget".endsWith("get") ); // true, "Widget" ends with "get"

Lấy một chuỗi con

Có 3 phương pháp trong hoạt Javascript để có được một chuỗi con: substring, substrslice.str.slice(start [, end])

Trả về một phần của chuỗi từ start(nhưng không bao gồm) end.




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/
*/

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

Nếu không có đối số thứ hai, thì hãy sliceđi đến cuối chuỗi:

let str = "stringify";
alert( str.slice(2) ); // 'ringify', from the 2nd position till the end

Giá trị cho start/endcũng có thể. Chúng có nghĩa là vị trí được tính từ cuối chuỗi:

let str = "stringify";

// start at the 4th position from the right, end at the 1st from the right
alert( str.slice(-4, -1) ); // 'gif'

Trả về một phần của chuỗi giữa startend.

Điều này gần giống như slice, nhưng nó cho phép startlớn hơn end.

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/
*/

let str = "stringify";

// these are same for substring
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)

Đối số phủ định là (không giống như slice) không được hỗ trợ, chúng được coi là

0.str.substr(start [, length])

Trả về một phần của chuỗi từ start, với cái đã cho length.

Ngược lại với các phương thức trước, phương thức này cho phép chúng ta chỉ định lengthvị trí thay vì vị trí kết thúc:




let str = "stringify";
alert( str.substr(2, 4) ); // 'ring', from the 2nd position get 4 characters

Đối số đầu tiên có thể là phủ định, để tính từ cuối:

let str = "stringify";
alert( str.substr(-4, 2) ); // 'gi', from the 4th position get 2 characters

Hãy tóm tắt lại các phương pháp này để tránh mọi nhầm lẫn:

phương thứcchọnphủ định
slice(start, end)từ startđến end(không bao gồm end)cho phép phủ định
substring(start, end)giữa startendgiá trị âm 0
substr(start, length)từ startnhận lengthnhân vậtcho phép tiêu cực start

Nên Chọn cái nào?

Tất cả đều có thể làm được việc. substrcó một nhược điểm nhỏ: nó được mô tả không phải trong đặc 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, 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 ở khắp mọi nơi.

Trong hai biến thể khác, slicelinh hoạt hơn một chút, nó cho phép viết các đối số phủ định và viết ngắn hơn. Vì vậy, chỉ cần nhớ sliceba phương pháp này là đủ.

So sánh chuỗi

Như chúng ta đã biết từ chương So sánh, các chuỗi được so sánh từng ký tự theo thứ tự bảng chữ cái.

Mặc dù, có một số điều kỳ lạ.

  1. Một chữ cái viết thường luôn lớn hơn chữ hoa: alert( 'a' > 'Z' ); // true

Các chữ cái có dấu phụ là dấu vết ngoài trật tự:

alert( 'Österreich' > 'Zealand' ); // true
  1. Đ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đến sau Österreichtrong danh sách.

Để hiểu điều gì xảy ra, hãy xem lại biểu diễn bên trong của chuỗi trong JavaScript.

Tất cả các chuỗi được mã hóa bằng UTF-16. Đó là: mỗi ký tự có một mã số tương ứng. Có các phương thức đặc biệt cho phép lấy ký tự cho mã và quay lại.str.codePointAt(pos)




Trả về mã cho ký tự ở vị trí pos:

// different case letters have different codes
alert( "z".codePointAt(0) ); // 122
alert( "Z".codePointAt(0) ); // 90

String.fromCodePoint(code)

Tạo một ký tự bằng số của nó code

alert( String.fromCodePoint(90) ); // Z

Chúng ta cũng có thể thêm các ký tự unicode bằng mã của chúng bằng cách sử dụng mã \uhex:

// 90 is 5a in hexadecimal system
alert( '\u005a' ); // Z

Bây giờ, hãy nhìn các ký tự có mã 65..220 (bảng chữ cái Latin) bằng cách tạo một chuỗi chúng:

let str = '';

for (let i = 65; i <= 220; i++) {
  str += String.fromCodePoint(i);
}
alert( str );
// ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ € ‚ƒ„
// ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ

Ký tự viết hoa đi trước, sau đó là một vài ký tự đặc biệt, rồi ký tự viết thường và Ö gần cuối của đầu ra.

Bây giờ nó trở nên rõ ràng tại sao từ a> Z.

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ã cho một chữ a(97) lớn hơn mã chữ Z(90).

  • Tất cả các chữ cái viết thường đi sau các chữ cái viết hoa vì mã của chúng lớn hơn.
    Một số chữ cái đứng ngoài bảng chữ cái chính. Ở đây, mã của nó lớn hơn bất cứ thứ gì từ a đến z.

So sánh đúng

Thuật toán bên phải để thực hiện so sánh chuỗi phức tạp hơn vẻ ngoài của nó, bởi vì bảng chữ cái khác nhau đối với các ngôn ngữ khác nhau.

Vì vậy, trình duyệt cần biết ngôn ngữ để so sánh.




May mắn thay, tất cả các trình duyệt hiện đại (IE10- yêu cầu thư viện bổ sung Intl.js) hỗ trợ tiêu chuẩn quốc tế hóa ECMA-402.

Nó cung cấp một phương thức đặ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.

Gọi hàm str.localeCompare(str2) trả về một số nguyên cho biết liệu str nhỏ hơn, bằng hay lớn hơn str2 theo quy tắc ngôn ngữ:

  • Trả về số âm nếu str nhỏ hơn str2.
  • Trả về số dương nếu str lớn hơn str2.
  • Trả về 0nếu chúng là tương đương.

Ví dụ:

alert( 'Österreich'.localeCompare('Zealand') ); // -1

Phương pháp này thực sự có hai đối số bổ sung quy định trong tài liệu, cho phép nó để xác định ngôn ngữ (theo mặc định lấy từ môi trường, trật tự phụ thuộc vào ngôn ngữ) và thiết lập thêm quy tắc nên "a""á"được đối xử như nhau vv .

Nội bộ, Unicode

Kiến thức nâng cao

Phần đi sâu hơn vào bên trong chuỗi. Kiến thức này sẽ hữu ích cho bạn nếu bạn có kế hoạch đối phó với biểu tượng cảm xúc, các ký tự toán học hoặc chữ tượng hình hiếm hoặc các biểu tượng hiếm khác.

Bạn có thể bỏ qua phần này nếu bạn không có kế hoạch hỗ trợ họ.

Cặp thay thế

Tất cả các ký tự được sử dụng thường xuyên có mã 2 byte. Các chữ cái trong hầu hết các ngôn ngữ châu Âu, số và thậm chí hầu hết các chữ tượng hình đều có biểu diễn 2 byte.

Nhưng 2 byte chỉ cho phép kết hợp 65536 và điều đó là không đủ cho mọi biểu tượng có thể. Vì vậy, các biểu tượng hiếm được mã hóa bằng một cặp ký tự 2 byte được gọi là một cặp thay thế.

Độ dài của các ký hiệu đó là 2:

alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X
alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY
alert( '𩷶'.length ); // 2, a rare Chinese hieroglyph

Lưu ý rằng các cặp thay thế không tồn tại tại thời điểm JavaScript được tạo và do đó ngôn ngữ không được xử lý chính xác!

Chúng tôi thực sự có một biểu tượng duy nhất trong mỗi chuỗi ở trên, nhưng lengthhiển thị độ dài 2.

String.fromCodePointstr.codePointAtlà một vài phương pháp hiếm hoi xử lý các cặp thay thế ngay. Họ gần đây đã xuất hiện trong ngôn ngữ. Trước họ, chỉ có String.fromCharCodestr.charCodeAt. Các phương thức này thực sự giống như fromCodePoint/codePointAt, nhưng không hoạt động với các cặp thay thế.

Lấy một biểu tượng có thể khó, bởi vì các cặp thay thế được coi là hai ký tự:

alert( '𝒳'[0] ); // strange symbols...
alert( '𝒳'[1] ); // ...pieces of the surrogate pair

Lưu ý rằng các mảnh của cặp thay thế không có ý nghĩa mà không có nhau. Vì vậy, các cảnh báo trong ví dụ trên thực sự hiển thị rác.

Về mặt kỹ thuật, các cặp thay thế cũng có thể được phát hiện bằng mã của chúng: nếu một ký tự có mã trong khoảng 0xd800..0xdbff, thì đó là phần đầu tiên của cặp thay thế. Ký tự tiếp theo (phần thứ hai) phải có mã trong khoảng 0xdc00..0xdfff. Các khoảng này được dành riêng cho các cặp thay thế theo tiêu chuẩn.

Trong trường hợp trên:

// 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

Bạn sẽ tìm thấy nhiều cách hơn để đối phó với các cặp thay thế sau này trong chương Iterables. Có lẽ có những thư viện đặc biệt cho điều đó, nhưng không có gì nổi tiếng đủ để đề xuất ở đây.

Dấu phụ và chuẩn hóa

Trong nhiều ngôn ngữ, có các ký hiệu được tạo thành từ ký tự cơ sở với một dấu ở trên / dưới nó.

Chẳng hạn, chữ cái acó thể là ký tự cơ sở cho : àáâäãåā. Hầu hết các ký tự phổ biến nhất có thể có mã riêng trong bảng UTF-16. Nhưng không phải tất cả trong số họ, bởi vì có quá nhiều sự kết hợp có thể.

Để hỗ trợ các bố cục tùy ý, UTF-16 cho phép chúng tôi sử dụng một số ký tự unicode: ký tự cơ sở theo sau là một hoặc nhiều ký tự đánh dấu trang mà mà trang trí của nó.

Chẳng hạn, nếu chúng ta đã Stheo sau dấu chấm đặc biệt trên đầu ký tự (mã \u0307), thì nó được hiển thị là.

alert( 'S\u0307' ); // Ṡ

Nếu chúng ta cần một dấu bổ sung phía trên chữ cái (hoặc bên dưới nó) – không có vấn đề gì, chỉ cần thêm ký tự đánh dấu cần thiết.

Chẳng hạn, nếu chúng ta nối thêm một ký tự điểm chấm bên dưới tên (mã \u0323), thì chúng ta sẽ có bản S với các dấu chấm ở trên và bên dưới chữ : .

Ví dụ:

alert( 'S\u0307\u0323' ); // Ṩ

Điều này cung cấp tính linh hoạt cao, nhưng cũng là một vấn đề thú vị: hai ký tự có thể trông giống nhau, nhưng được thể hiện bằng các thành phần unicode khác nhau.

Ví dụ:

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 (?!)

Để giải quyết vấn đề này, tồn tại một thuật toán bình thường hóa unicode, đưa từng chuỗi vào dạng đơn giản bình thường.

Nó được thực hiện bởi str.normalize().

alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true

Thật buồn cười là trong tình huống của chúng tôi normalize()thực sự tập hợp một chuỗi gồm 3 ký tự thành một: \u1e68(S có hai dấu chấm).

alert( "S\u0307\u0323".normalize().length ); // 1

alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true

Trong thực tế, điều này không phải lúc nào cũng đúng. Lý do là biểu tượng đó là một điểm chung đủ phổ biến, vì vậy những người tạo UTF-16 đã đưa nó vào bảng chính và cung cấp cho nó mã.

Nếu bạn muốn tìm hiểu thêm về các quy tắc và biến thể chuẩn hóa – chúng được mô tả trong phần phụ lục của tiêu chuẩn Unicode : Các hình thức chuẩn hóa Unicode , nhưng đối với hầu hết các mục đích thực tế, thông tin từ phần này là đủ.

Tóm lược

  • Có 3 loại trích dẫn. Backticks cho phép một chuỗi trải rộng nhiều dòng và nhúng biểu thức ${…}.
  • Các chuỗi trong JavaScript được mã hóa bằng UTF-16.
  • Chúng ta có thể sử dụng các ký tự đặc biệt như \nvà chèn các chữ cái bằng unicode của chúng bằng cách sử dụng \u....
  • Để có được một ký tự, sử dụng : [].
  • Để có được một chuỗi con, sử dụng: slicehoặc substring.
  • Để viết thường / viết hoa một chuỗi, sử dụng : toLowerCase/toUpperCase.
  • Để tìm chuỗi con, sử dụng: indexOfhoặc includes/startsWith/endsWithđể kiểm tra đơn giản.
  • Để so sánh các chuỗi theo ngôn ngữ, sử dụng : localeCompare, nếu không, chúng được so sánh bằng mã ký tự.

Có một số phương thức hữu ích khác trong chuỗi:

  • str.trim() – loại bỏ khoảng trống từ đầu và cuối chuỗi.
  • str.repeat(n)– lặp lại chuỗi nlần.
  • và nhiều thứ hơn nữa được tìm thấy trong hướng dẫn.

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, vì vậy nó được giải thích trong phần hướng dẫn riêng biệt.