String

Duy Văn | 06/02/2025


  1. Giới thiệu
  2. Methods

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ả ra undefined, 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 đến end (start là inclusive, end là exclusive)
  • substring(start,end): Cắt từ vị trí start đến end (start là inclusive, end là exclusive)
  • substr(start,length): Cắt từ vị trí start với độ dài length Với start và end là 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"]

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