Câu 1Với const quantity = 3;, thứ gì được nhúng vào chỗ ${quantity * 1200} xuất hiện trong một template literal?
Chuỗi và Template Literal
Học chuỗi trong JavaScript: chọn kiểu dấu ngoặc, nhúng giá trị bằng template literal, tách và thay thế.
Văn bản bạn hiển thị trên màn hình, dữ liệu nhập từ form, tên sản phẩm trả về từ một API — rất nhiều giá trị mà một ứng dụng web xử lý là chuỗi (string) (giá trị gồm một dãy ký tự).
Bài này nói về xây dựng chuỗi với 3 kiểu dấu ngoặc và template literal, rồi các phương thức để dọn dữ liệu nhập thành dạng hiển thị được: cắt khoảng trắng, kiểm tra có chứa gì không, tách và ghép lại, và căn chỉnh chữ số.
Xây Dựng và Dọn Dẹp Chuỗi — 3 Kiểu Dấu Ngoặc và Template Literal
Giả sử bạn muốn màn hình xác nhận đơn hàng hiện "Insulated Mug x 3 / Total 3600" — tên sản phẩm, số lượng, và số tiền mỗi thứ nằm trong biến riêng. Ghép chúng thành một câu chính là việc xây dựng chuỗi. Hãy bắt đầu với cách viết một chuỗi trước tiên.
Một chuỗi được viết bọc trong nháy đơn ', nháy kép ", hoặc backtick. Nếu chính ký tự nháy bạn dùng để bọc xuất hiện bên trong, nó sẽ bị đọc là kết thúc chuỗi, nên để chứa ký tự nháy bên trong, hoặc bọc bằng kiểu nháy khác hoặc đặt \ trước nó để hủy ý nghĩa đặc biệt.
Bạn sẽ thấy một backtick thật trong ví dụ code sắp tới.
const productName = "Insulated Mug"; // bọc bằng nháy kép
const categoryName = 'Kitchen Goods'; // bọc bằng nháy đơn
// Thoát bằng \ để chứa cùng loại nháy bạn đã dùng để bọc
const notice = "Staff \"Pick\"";
// Bọc bằng loại nháy khác thì không cần thoát
const notice2 = 'Staff "Pick"';
console.log(productName.length); // 13 số ký tự trả về dưới dạng số
console.log(notice); // Staff "Pick"
console.log(notice2); // Staff "Pick"
length, trả về số ký tự, là một property (thông tin gắn với một giá trị, đọc bằng tên mà không cần dấu ngoặc). Khác với một phương thức như toFixed ở bài trước, bạn không viết dấu ngoặc — không phải productName.length().
Chuỗi có thể nối bằng +, nhưng càng thêm nhiều biến, dấu nháy và dấu + càng chất chồng và khó đọc. Đó là lý do có template literal (bọc chuỗi trong backtick, và bất kỳ giá trị nào viết trong ${ } sẽ được nhúng vào).
Bên trong ${ } bạn có thể viết không chỉ một biến mà cả một biểu thức như unitPrice * quantity, và kết quả tính toán sẽ được nhúng vào.
${ } được tính trước, rồi ghép vào chuỗi. Xuống dòng giữ nguyên như đã viết.const productName = "Insulated Mug";
const unitPrice = 1200;
const quantity = 3;
// Nối bằng + trộn lẫn nháy và +
console.log(productName + " x " + quantity + " / Total " + unitPrice * quantity);
// Với ${ }, cả giá trị lẫn biểu thức đều viết được nguyên trạng
console.log(`${productName} x ${quantity} / Total ${unitPrice * quantity}`);
// Cả hai in ra: Insulated Mug x 3 / Total 3600
Dọn Dẹp Để Hiển Thị — trim / slice / toUpperCase
Một cái tên gõ vào form có thể có khoảng trắng thừa xung quanh, hoặc chữ hoa/thường không nhất quán. Hiển thị nguyên trạng có thể trông như bị lỗi, nên bạn dọn dẹp hình dạng của nó ngay trước khi hiển thị.
trim bỏ khoảng trắng xung quanh, toUpperCase chuẩn hóa thành chữ hoa, và slice cắt một phần của chuỗi.
slice nhận vị trí bắt đầu và vị trí kết thúc. Vị trí đếm từ 0, và ký tự tại vị trí kết thúc không được tính vào.
slice(0, 1) cho bạn ký tự đầu tiên; bỏ qua phần cuối, như slice(1), và bạn nhận mọi thứ từ đó đến hết chuỗi.
const rawInput = " Minh "; // giá trị nhận từ một ô nhập liệu
console.log(rawInput.trim()); // Minh
console.log(rawInput.trim().length); // 4
console.log(rawInput.trim().toUpperCase()); // MINH
console.log(rawInput.trim().slice(0, 2)); // Mi 2 ký tự đầu
// Bạn có thể nối các kết quả cắt lại bằng +
console.log(rawInput.trim().slice(0, 1).toUpperCase() + "…"); // M…
console.log(rawInput.length); // 9 bản gốc vẫn còn khoảng trắng
Phương Thức Không Thay Đổi Chuỗi Gốc
trim và toUpperCase chỉ trả về kết quả đã dọn dẹp dưới dạng chuỗi mới — biến bạn gọi chúng trên đó giữ nguyên hoàn toàn. Để dùng kết quả, hãy lưu vào biến hoặc nối tiếp vào lần gọi phương thức kế tiếp, như trong ví dụ trên.
Tìm Kiếm Bên Trong Chuỗi — includes / startsWith / indexOf
Nếu địa chỉ email người dùng gõ không có @, bạn sẽ muốn từ chối trước khi lưu. Hoặc có thể bạn muốn xử lý mã đơn hàng khác nhau tùy vào việc nó có bắt đầu bằng ORD- hay không. Những kiểm tra như thế này dùng các phương thức tìm kiếm bên trong chuỗi.
includes trả về true hoặc false cho một chuỗi cho trước có xuất hiện ở đâu đó không, và startsWith cho chuỗi có bắt đầu bằng nó không.
Khi bạn cần vị trí thật sự, dùng indexOf, trả về vị trí, dưới dạng số, của lần khớp đầu tiên. Nếu không có gì khớp, nó trả về -1, nên nó cũng đóng vai trò cách kiểm tra có chứa gì đó không.
true hoặc false).const orderCode = "ORD-2026-0042";
console.log(orderCode.includes("2026")); // true có chứa ở đâu đó
console.log(orderCode.startsWith("ORD-")); // true phần đầu khớp
console.log(orderCode.indexOf("-")); // 3 vị trí, đếm từ 0
console.log(orderCode.indexOf("SHIP")); // -1 không tìm thấy
console.log(orderCode.slice(4)); // 2026-0042 từ vị trí 4 đến hết
Kết hợp vị trí mà indexOf trả về với slice, và bạn có thể lấy ra đúng phần sau một ký tự phân cách. Một khi biết @ nằm ở đâu, truyền cho slice vị trí ngay sau đó sẽ cho bạn phần domain của một địa chỉ email.
Tách và Ghép Lại — split và join
Đôi khi, như một dòng CSV hay ô nhập tag, một chuỗi duy nhất chứa nhiều giá trị. Xử lý từng mục riêng lẻ nghĩa là tách theo ký tự phân cách, và làm ngược lại — để hiển thị — nghĩa là ghép chúng trở lại thành một. split làm việc tách; join làm việc ghép.
split nhận ký tự để tách theo. split(",") tách tại mỗi dấu phẩy, và kết quả trả về là một mảng (array) (nhiều giá trị xếp theo thứ tự và gói vào một giá trị). join chạy theo hướng ngược lại — truyền cho nó ký tự để đặt giữa các mục, và nó ghép chúng lại thành một chuỗi duy nhất.
split tách một chuỗi thành mảng tại ký tự phân cách; join đặt ký tự giữa các mảnh để ghép chúng lại thành một chuỗi.const tagLine = "Kitchen,Insulated,Gift"; // nội dung một ô nhập tag
const tags = tagLine.split(","); // tách tại mỗi dấu phẩy
console.log(tags.length); // 3 số mảnh
console.log(tags[0]); // Kitchen vị trí 0 = giá trị đầu
console.log(tags[2]); // Gift vị trí 2 = giá trị thứ ba
console.log(tags.join(" / ")); // Kitchen / Insulated / Gift
console.log("2026-09-02".split("-").join("/")); // 2026/09/02
Lấy Giá Trị Đã Tách Ra Theo Vị Trí
Từ mảng mà split trả về, lấy từng mục một bằng cách viết vị trí của nó, đếm từ 0, trong dấu ngoặc vuông — như tags[0]. Các thao tác trên chính mảng, như thêm hay bớt mục, sẽ nói lại trong bài về mảng.
Thay Thế và Đệm — replaceAll và padStart
Có thể bạn muốn bỏ dấu gạch ngang khỏi một số điện thoại trước khi lưu, hoặc đệm một mã đơn hàng thành 6 chữ số với số 0 phía trước để hiển thị. Với các việc "định dạng lại một chuỗi nhận được thành một khuôn cố định" như thế này, dùng replaceAll và padStart.
replaceAll nhận chuỗi cần tìm và chuỗi để thay thế. Thay bằng một chuỗi rỗng "" (chuỗi độ dài 0, không có gì giữa hai dấu nháy), và điều đó có tác dụng như xóa ký tự.
padStart nhận độ dài mục tiêu và ký tự để đệm (mặc định là dấu cách nếu bạn bỏ qua), và thêm ký tự đệm đó vào phía trước cho đủ độ dài còn thiếu. Nếu chuỗi gốc đã đủ dài hoặc dài hơn, không có gì được thêm vào — nó trả về nguyên trạng.
const rawCode = "ord 2026 0042"; // mã đơn hàng gõ với khoảng trắng
console.log(rawCode.replaceAll(" ", "-")); // ord-2026-0042
console.log("090-1234-5678".replaceAll("-", "")); // 09012345678
console.log("42".padStart(6, "0")); // 000042 đệm 0 cho đủ 6 chữ số
console.log("42".padStart(6)); // 42 không có ký tự đệm nghĩa là dấu cách
console.log("1200".padStart(3, "0")); // 1200 đã đủ 3+ chữ số, không đổi
Kiểm tra kiến thức
Hãy trả lời từng câu hỏi một.
Câu 2Đoạn code này hiển thị gì?const rawName = " hanh ";rawName.trim();console.log(rawName.length);
Câu 3console.log("1234567".padStart(6, "0")); hiển thị gì?