String
Duy Văn | 06/02/2025
Giới thiệu
Strings về cơ bản là các giá trị text, các giá trị này là các literals và sẽ cần được gán cho biến. Ví dụ:
let a = "Hello World";
Thông thường, Strings sẽ được bọc bởi single-quote ' hoặc double-quote ". Và strings có chứa double-quote có thể được bọc trong single quote và ngược lại. Ví dụ:
let a = 'Hello "World"';
let b = "Hello 'World'";
Nếu gói ở trong một strings là dấu cùng kiểu ,ví dụ “Đây là “tôi”” thì dấu cùng kiểu bên trong sẽ phải được escape bằng dấu \. Ví dụ:
let a = "Đây là \"tôi\"";
let b = 'Đây là \'tôi\'';
Đồng thời, dấu / cũng cần escape và chỉ // mới được hiểu trong strings là /. Ví dụ:
let a = "Đây là \\"; // Đây là \
Ngoài ra có \n để xuống dòng, \t để tab, \v để vertical tab là nên nhớ
Convention mới ở ES6 cho phép gói Strings lại trong dấu backticks `. Điều này cho phép sử dụng template literals, tức là có thể chèn biến vào trong string một cách dễ dàng. Ví dụ:
let a = "Hello", b = "World";
console.log(`${a} ${b}`); // Hello World
Đồng thời khi được gói trong backticks thì strings có thể có single quote và double quote. Ví dụ:
let a = `Hello 'World'`;
let b = `Hello "World"`;
Bình thường thì bản thân strings là giá trị nguyên thuỷ, tạo ra từ literal là bản thân string đấy. Tuy nhiên có một cách define string từ một object, đó là new String(). Ví dụ:
let a = "Hello";
let b = new String("Hello");
Object String này thật sự không có quá nhiều ứng dụng khi được khởi tạo, nhưng quy luật thông thường là chúng ta không nên chủ động tạo ra các object string mà nên sử dụng literals. Object string sẽ chỉ nên sử dụng khi ép kiểu qua lại cho dữ liệu.
Methods
Có một loạt các methods có sẵn để làm việc với Strings, một số sẽ có sự tương đồng với phía Python, nhưng cũng do cách string hoạt động trong JS khác với trong Python nên cũng có sự khác biệt.
Length
length là một thuộc tính của String, không phải một hàm như bên Python. Nó trả về độ dài của string. Ví dụ:
let a = "Hello";
console.log(a.length); // 5
Còn ở phía Python, len() là một hàm, không phải một thuộc tính. Nó lấy vào đối tượng là một iterable và trả về độ dài của nó.
Indexing
Để lấy ra các ký tự trong string của JS, chúng ta có một số cách sau
charAt()
charAt() là một method trả về ký tự ở vị trí chỉ định trong string. Ví dụ:
let a = "Hello";
console.log(a.charAt(1)); // e
Vấn đề với charAt() là nó rất thiếu tự nhiên và không thân thiện với coder.
charCodeAt()
charCodeAt() trả về mã Unicode của ký tự ở vị trí chỉ định trong string. Ví dụ:
let a = "Hello";
console.log(a.charCodeAt(1)); // 101
Mã Unicode của ký tự e là 101.
Với charCodeAt(), nó sẽ chỉ ra mã UTF-16 của ký tự, không phải mã Unicode. Tức là đối với UTF-16 , giá trị trả ra sẽ nằm trong khoảng 0 - 65535. Còn với Unicode, giá trị lớn nhất là 1114111
Để lấy mã Unicode của 1 ký tự, dùng codePointAt(), nó sẽ trả về mã Unicode của ký tự ở vị trí chỉ định trong string. Nhưng format vẫn tuân theo UTF-16 chứ không thật sự là Unicode code point
at()
Với ES2022, at() được đưa vào để cũng trả về ký tự nằm ở vị trí (index) chỉ định trong string
let a = "Hello";
console.log(a.at(1)); // e
[]
Cuối cùng là cách indexing thông thường được thêm vào cũng ở ES2022
let a = "Hello";
console.log(a[1]); // e
Việc cho phép sử dụng [] để lấy ký tự string gần giống như bên Python, tuy nhiên bản thân string không phải array, một số đặc điểm:
- Nếu không có ký tự (index quá giới hạn) thì
[]và.at()trả raundefined, còn như charAt() sẽ trả rỗng
Đồng thời, String có thể hiểu là immutable, vì thế không thể thay đổi giá trị của nó thông qua index như array.
Slice
Với string trong JS, chúng ta cũng có thể cắt một đoạn nhỏ của nó ra, khác so với Python, JS có:
slice(start,end): Cắt từ vị trístartđếnend(start là inclusive, end là exclusive)substring(start,end): Cắt từ vị trístartđếnend(start là inclusive, end là exclusive)substr(start,length): Cắt từ vị trístartvới độ dàilengthVớistartvàendlà index của ký tự trong string
slice()
let a = "Hello";
console.log(a.slice(1,3)); // el
Trong trường hợp chỉ đưa vào 1 param, thì sẽ tự coi arg là index start và end lấy giá trị default là length của string, tức là sẽ cắt từ start đến hết string
let a = "Hello";
console.log(a.slice(1)); // ello
Trong tình huống arg đưa vào là số âm, nó sẽ lấy từ vị trí đếm từ cuối đến lên tới hết string
let a = "Hello";
console.log(a.slice(-3)); // llo
Dấu của index chỉ ảnh hưởng đến cách đếm từ đầu hay từ cuối lên, chứ không ảnh hưởng đến hướng cắt, khác với bên Python
substring()
substring tương tự như slice
substr()
Cách hoạt động theo index của nó giống, nhưng param thứ hai nó lấy vào không phải là index của ký tự cuối cùng mà là độ dài của string cần cắt
let a = "Hello";
console.log(a.substr(1,3)); // ell
Về mặt toán học, nó sẽ thường cho kết quả giống với slice. nhưng param thứ 2 không thể âm, nếu âm thì nó sẽ coi như 0 và trả ra string rỗng
Convert Upper Lower
String được đưa lên uppercase với toUpperCase(), và lowercase với toLowerCase(). Ví dụ:
let a = "Hello";
console.log(a.toUpperCase()); // HELLO
console.log(a.toLowerCase()); // hello
Nó sẽ áp dụng cho toàn bộ string, nếu cần thực hiện thay đổi ở một số index nhất định thì phải áp dụng logic và tạo string mới
Concetenate
Để thêm các string vào với nhau thì có thể sử dụng method concat() hoặc operator +, về cơ bản là y hệt nhau và đều cần gán nó vào string mới
let a = "Hello";
let b = "World";
console.log(a.concat(b)); // HelloWorld
console.log(a + b); // HelloWorld
Số lượng arg của concat() không giới hạn, và nó sẽ thêm các string vào cuối string gốc
let a = "Hello";
let b = "World";
let c = "!";
console.log(a.concat(b,' ', c)); // Hello World!
Trim
trim() sẽ loại bỏ các khoảng trắng ở đầu và cuối string. Ví dụ:
let a = " Hello World ";
console.log(a.trim()); // Hello World
Nếu chỉ muốn loại bỏ ở đầu hoặc cuối thì có thể sử dụng trimStart() hoặc trimEnd()
Pad
padStart() và padEnd() sẽ thêm vào đầu hoặc cuối string một số lượng ký tự cho trước, nếu string gốc đã dài hơn số lượng ký tự cần thêm thì nó sẽ không thêm gì cả. Ví dụ:
let a = "Hello";
console.log(a.padStart(10, "a")); // aaaaaHello
console.log(a.padEnd(10, "a")); // Helloaaaaa
Đây là một method của String và không dùng được cho số, vì thế nếu dùng trick lỏ để chơi leetcode thì cần convert số về string trước
Repeat
repeat() sẽ lặp lại string n lần. Ví dụ:
let a = "Hello";
console.log(a.repeat(3)); // HelloHelloHello
Thay nội dung
replace() sẽ thay thế nội dung trong string với pattern cho trước. Ví dụ:
let a = "Hello World";
console.log(a.replace("World", "Duy")); // Hello Duy
replace() sẽ chỉ thay thế nội dung đầu tiên mà nó tìm thấy, nếu muốn thay tất cả thì cần sử dụng RegEx
Kết hợp với RegEx thì sẽ rất mạnh, giả sử cho một string có toàn chữ và số, muốn thay tất cả số thành dấu * thì có thể dùng
let a = "Hello 123 World 456";
console.log(a.replace(/\d/g, "*")); // Hello *** World ***
Ngoài ra trong tình huống 1 ký tự lặp lại nhiều lần, có thể dùng replaceAll() để thay hết
let a = "Hello 123 World 123";
console.log(a.replaceAll("123", "*")); // Hello * World *
Convert thành array
Đưa string về array ở JS rất giống Python, dùng split(). Ví dụ:
let a = "Hello World";
console.log(a.split(" ")); // ["Hello", "World"]
Với argument sẽ là dấu phân cách, nếu không có argument thì nó sẽ cắt từng ký tự ra, khác với bên Python default sẽ là dấu cách
let a = "Hello World";
console.log(a.split("")); // ["H", "e", "l", "l", "o", " ", "W", "o", "r", "l", "d"]
Method Search
String search là nhóm method String để tìm và xác định một string hoặc một pattern trong string. Có 4 method chính:
search(): Tìm kiếm một pattern trong string, trả về index của pattern đầu tiên tìm thấy, nếu không tìm thấy trả về -1
let a = "Hello World";
console.log(a.search("World")); // 6
indexOf(): Tìm kiếm một pattern trong string, trả về index của pattern đầu tiên tìm thấy, nếu không tìm thấy trả về -1. Nó cũng nhận thêm một argument nữa là index để bắt đầu tìm kiếm (từ đầu đến index đó sẽ không được tìm)
let a = "Hello World";
console.log(a.indexOf("o")); // 6
console.log(a.indexOf("o", 5)); // 7
lastIndexOf(): tương tự nhưindexOf()nhưng tìm từ cuối string lên, hay nói chuẩn hơn là tìm index của lần xuất hiện cuối cùng
indexOf() và lastIndexOf() không thể dùng với RegEx
search() có thể dùng RegEx nhưng không thể lấy vào argument thứ hai
Match
Về cơ bản thì match() sẽ trả về một array chứa các kết quả tìm thấy, nếu không tìm thấy thì trả về null. Ví dụ:
let a = "Hello World";
console.log(a.match("o")); // ["o"]
Nhìn thì có vẻ đầu đất nhưng bản thân match sinh ra là để làm việc với RegEx và nó cực kỳ mạnh mẽ trong việc này
let a = "Hello World Halla";
console.log(a.match(/\bH\w*/g)); // ["Hello","Halla"]
String Template
String Template là phát kiến của ES6, cho phép chèn biến vào string một cách dễ dàng. Ví dụ:
let a = "Hello", b = "World";
console.log(`${a} ${b}`); // Hello World
Đồng thời, các string ở trong template literals có thể chứa single quote và double quote mà không cần escape
let a = `Hello 'World'`;
let b = `Hello "World"`;
Nó cũng cho phép có nhiều dòng
let a = `Hello
World`;
Lợi dụng chèn biến, chúng ta có thể chèn vào cả biểu thức
let a = 10, b = 20; c = 6;
console.log(`Expression ${(a+b)*c}`); // Expression 180