Học bằng cách đọc theo thứ tự

Spread Syntax — Sao Chép, Kết Hợp, và Ghi Đè Cài Đặt

Học spread syntax: bung nội dung mảng hay object ra tại chỗ để sao chép và gộp mà không đổi bản gốc.

Gộp một danh sách sản phẩm còn hàng với một danh sách đặt trước thành một. Chỉ xếp chồng các trường người dùng đã đổi lên trên cài đặt mặc định. Trong các trường hợp như thế này, bạn xây một mảng hay object mới với nội dung được trải ra, trong khi giữ dữ liệu gốc đúng như nó vốn có.

Bài này nói về spread syntax cho việc đó, và giá trị nào thắng khi cùng một key xuất hiện hai lần.

Trải Nội Dung Ra Tại Chỗ — Spread Syntax

Muốn gộp một danh sách sản phẩm còn hàng với một danh sách đặt trước thành một? Thêm từng cái bằng push, và mảng gốc bị ghi đè. Đây là trường hợp bạn muốn xây một mảng mới với nội dung được trải ra, trong khi giữ các danh sách gốc đúng như chúng vốn có.

Spread syntax (viết ... trước một giá trị để trải nội dung của mảng hay object ra tại chỗ) cho phép bạn viết const allItems = [...inStock, ...backOrder]; để xây một mảng mới, đã gộp. Chỉ viết một cái, như [...inStock], và đó là một bản sao — một mảng riêng với cùng nội dung.

Object hoạt động giống vậy, với { ...product }. Lưu ý đây là một bản sao chỉ ở cấp đầu tiên — hành vi khi có một object hay mảng lồng bên trong sẽ nói ở bài về tham chiếu và sao chép.

... đóng vai trò khác nhau tùy vào chỗ bạn viết nó. Ở bên trái của =, nó là rest, gộp phần còn dư. Trong [] hay {} ở bên phải, nó là spread, trải nội dung ra. Cùng một ký hiệu, nhưng gộp và trải chạy theo hướng ngược nhau.

... Trải Nội Dung Ra Tại Chỗ
[...inStock]Trải nội dungnguyên trạngMảng riêng,cùng nội dung[...inStock,...backOrder]Trải theo thứtự đã viếtMảngđã gộp["New",...inStock]Thêm 1 mụcở đầuMảng nhiềuhơn 1 mục
Chúng đi vào mảng mới theo thứ tự bạn viết. Mảng gốc không bị ghi đè.
const inStock = ["Wireless Mouse", "USB-C Hub"];
const backOrder = ["Monitor Arm"];

// Xây một mảng mới trải cả hai
const allItems = [...inStock, ...backOrder];
console.log(allItems.join(", "));   // Wireless Mouse, USB-C Hub, Monitor Arm

// Mảng gốc không đụng tới
console.log(inStock.length);        // 2

// Bạn có thể trộn một giá trị riêng lẻ vào giữa
const featured = ["This Week's Pick", ...inStock];
console.log(featured.length);       // 3

// Object cũng sao chép được theo cùng cách
const product = { name: "USB-C Hub", price: 2480 };
const copied = { ...product };
console.log(copied.price);          // 2480

Xây một mảng hiển thị từ 2 mảng — còn hàng và đặt trước. inStockbackOrder đã được khai báo sẵn.

① Xây một mảng mới gộp cả hai, và hiển thị ghép bằng ", ".

② Hiển thị số lượng của mảng đã gộp.

③ Xây một mảng thêm "New Arrival" vào đầu mảng đã gộp, và hiển thị 2 mục đầu tiên ghép bằng ", ".

④ Xây một mảng mới sao chép mảng còn hàng, và hiển thị số lượng của nó.

(Nếu chạy đúng, phần giải thích sẽ xuất hiện.)

JavaScript / TypeScript Editor

Chạy code để xem đầu ra

Viết lại một mảng hay object đã sao chép và xem chuyện gì xảy ra với bản gốc. inStockproduct đã được khai báo sẵn.

① Xây một bản sao của inStock, thêm "HDMI Cable" vào đó, và hiển thị số lượng của nó.

② Hiển thị số lượng của inStock gốc.

③ Xây một bản sao của product, đổi giá thành 1980, và hiển thị.

④ Hiển thị giá của product gốc.

JavaScript / TypeScript Editor

Chạy code để xem đầu ra

Xếp Chồng Cài Đặt — Giá Trị Viết Sau Thắng

Cài đặt của một ứng dụng đôi khi được thiết lập với một vòng mặc định đầy đủ, rồi chỉ những trường người dùng đã đổi mới bị ghi đè lên. Kiểm tra và gán từng trường đã đổi một lần lượt, tuy nhiên, và bạn sẽ cần thêm code mỗi khi một cài đặt mới xuất hiện.

Xếp hai object spread cạnh nhau, như { ...defaultSettings, ...userSettings }, và một key chung sẽ bị ghi đè bởi giá trị nào được viết sau. Một key người dùng chưa chỉ định giữ nguyên ở mặc định.

Thứ tự bạn viết chúng trực tiếp trở thành mức ưu tiên, nên đặt mặc định trước và cái bạn muốn ưu tiên sau.

Khi Xếp Chồng, Cái Viết Sau Thắng
mặc định themelightdark viếtsaudarkmặc định count2050 viếtsau50mặc định notifytrueKhông có keykhớp ở phía sauvẫn là true
Một key chung bị ghi đè bởi giá trị từ object viết sau; một key chỉ tồn tại ở một bên giữ nguyên đúng như nó vốn có.
const defaultSettings = { theme: "light", itemsPerPage: 20, notifications: true };
const userSettings = { theme: "dark" };

const merged = { ...defaultSettings, ...userSettings };
console.log(merged.theme);           // dark (cái viết sau thắng)
console.log(merged.itemsPerPage);    // 20 (thiếu ở phía người dùng, nên mặc định giữ nguyên)

// Đảo thứ tự, và mặc định thắng thay vào đó
const reversed = { ...userSettings, ...defaultSettings };
console.log(reversed.theme);         // light

// Ngay cả một giá trị undefined cũng ghi đè, miễn key tồn tại ở phía sau
const partial = { theme: undefined };
const broken = { ...defaultSettings, ...partial };
console.log(broken.theme);           // undefined

Ngay Cả undefined Cũng Ghi Đè

Miễn là key tồn tại ở phía bạn đang xếp chồng lên, nó ghi đè — ngay cả khi giá trị là undefined. Xếp chồng một trường chưa điền thẳng từ một form lên như vậy, và mặc định biến mất, thay bằng undefined. Với một trường bạn chỉ muốn dùng khi nó thực sự có giá trị, kiểm tra từng cái một, như userSettings.theme ?? defaultSettings.theme.

Xếp chồng thay đổi của người dùng lên cài đặt mặc định để xây cài đặt bạn thực sự dùng. defaultSettingsuserSettings đã được khai báo sẵn.

① Xây một object xếp chồng cài đặt người dùng lên mặc định, và hiển thị nguyên trạng.

② Hiển thị theme của kết quả đã xếp chồng.

③ Xây một object với thứ tự xếp chồng đảo ngược, và hiển thị theme của nó.

④ Hiển thị chuyện gì xảy ra với cài đặt notifications, phía người dùng không có, trong kết quả đã xếp chồng.

JavaScript / TypeScript Editor

Chạy code để xem đầu ra
QUIZ

Kiểm tra kiến thức

Hãy trả lời từng câu hỏi một.

Câu 1Viết const copied = [...items];, rồi copied.push("X"). Chuyện gì xảy ra với items gốc?

Câu 2Với const merged = { ...defaults, ...user };, chuyện gì xảy ra với một key tồn tại ở cả hai bên?

Câu 3Object bạn đang xếp chồng lên có key đó, nhưng giá trị của nó là undefined. Chuyện gì xảy ra với mặc định?