← Lập trình JavaScript cơ bản

Bài 5 · Vận dụng · 22 phút· Cập nhật 11/06/2026

Mảng & object

Biên soạn bởi Nguyễn Anh Tuấn

Xử lý mảng & object trong JavaScript: map/filter/reduce, destructuring, spread (sao chép nông), và JSON.stringify/parse để lưu & trao đổi dữ liệu.

Mảng (array) giữ nhiều giá trị theo thứ tự, truy cập bằng chỉ số (bắt đầu từ 0). Mảng thực ra là một loại object, nên có sẵn nhiều method tiện lợi:

mảng cơ bản

const diem = [8, 9, 7, 10];

diem[0];            // 8     (chi so tu 0)
diem.length;        // 4
diem.push(6);       // them cuoi  -> [8, 9, 7, 10, 6]
diem.pop();         // bo cuoi    -> [8, 9, 7, 10]
diem.includes(9);   // true
  • Chỉ số từ 0; diem.length là số phần tử.
  • Thêm/bớt: push/pop (cuối), shift/unshift (đầu).
  • Mảng là object (typeof [] là "object"); kiểm tra bằng Array.isArray(x).

Ba method này nhận một callback (hàm hạng nhất - bài 4) và không sửa mảng gốc. map biến đổi từng phần tử → mảng MỚI; filter giữ phần tử thoả điều kiện → mảng MỚI; find trả về phần tử ĐẦU TIÊN thoả điều kiện - chính phần tử có sẵn trong mảng, không tạo gì mới.

ba method chủ lực

const diem = [8, 9, 7, 10];

diem.map((d) => d * 2);       // [16, 18, 14, 20]  (cung do dai)
diem.filter((d) => d >= 9);   // [9, 10]           (loc)
diem.find((d) => d < 8);      // 7                 (phan tu dau tien thoa)

console.log(diem);            // [8, 9, 7, 10]     (goc KHONG doi)
  • map: biến đổi từng phần tử → mảng mới CÙNG độ dài.
  • filter: giữ phần tử thoả điều kiện → mảng mới ngắn hơn/bằng.
  • find: phần tử ĐẦU TIÊN thoả (some/every trả về true/false).
  • Tất cả nhận callback và KHÔNG sửa mảng gốc.

reduce là method mạnh nhất trong nhóm: nó đi qua mảng, mang theo một accumulator (acc) và cập nhật acc = fn(acc, cur) mỗi bước. Bấm để xem acc “gối đầu” qua từng phần tử:

Mảng:
Phép:
[1, 2, 3, 4].reduce((acc, cur) => acc + cur, 0)
Bướcacccur→ acc mới
khởi tạo0
i=00+11
i=11+23
i=23+36
i=36+410
Kết quả: 10 - gộp 4 phần tử về MỘT giá trị.

reduce(callback, init)

const diem = [8, 9, 7, 10];

const tong = diem.reduce((acc, d) => acc + d, 0);   // 34
const tich = diem.reduce((acc, d) => acc * d, 1);   // 5040
const max = diem.reduce((acc, d) => Math.max(acc, d), 0);   // 10
  • reduce(callback, init): acc bắt đầu từ init, mang qua từng bước.
  • acc của bước sau = kết quả của bước trước (gối đầu).
  • Tổng, tích, max, đếm, nhóm… đều làm được bằng reduce.

Đừng quên init

Hãy LUÔN truyền giá trị khởi tạo (đối số thứ 2). Mảng rỗng + không có init → lỗi “Reduce of empty array with no initial value”. Có init thì mảng rỗng trả về chính init - an toàn và dễ đọc.

Object gom dữ liệu thành các cặp khoá-giá trị. Truy cập bằng dấu chấm, hoặc ngoặc vuông khi khoá là động. Lặp qua khoá bằng Object.keys/values/entries:

object & method

const sv = {
  ten: "Lan",
  tuoi: 16,
  chao() { return "Chao " + this.ten; },   // method (this - bai 3)
};

sv.ten;            // "Lan"   (dot)
sv["tuoi"];        // 16      (bracket - khi khoa dong)
Object.keys(sv);   // ["ten", "tuoi", "chao"]
sv.chao();         // "Chao Lan"
  • Object = các cặp khoá-giá trị; truy cập dot (sv.ten) hoặc bracket (sv["ten"]).
  • Bracket dùng khi khoá nằm trong biến: sv[key].
  • Object.keys / values / entries để lặp; method bên trong dùng this.

Destructuring lấy nhanh giá trị ra khỏi mảng/object. Spread (...) trải phần tử ra để sao chép & gộp; còn rest (cùng ký hiệu) gom phần còn lại lại.

lấy ra, sao chép, gộp

const sv = { ten: "Lan", tuoi: 16 };
const { ten, tuoi } = sv;               // destructuring object

const [dau, ...con_lai] = [1, 2, 3];    // dau = 1; con_lai = [2, 3]  (rest)

const them = { ...sv, lop: "11A" };     // spread: sao chep + them field
const gop = [...[1, 2], ...[3, 4]];     // [1, 2, 3, 4]
  • Destructuring: lấy field/phần tử ra biến trong một dòng (hợp với tham số hàm).
  • Spread ...: sao chép & gộp mảng/object; rest ...: gom phần còn lại.
  • Spread là sao chép NÔNG - dữ liệu lồng bên trong vẫn chung tham chiếu.

Nông chứ không sâu

const b = {...a} chỉ sao chép một lớp. Nếu a chứa mảng/object lồng nhau, thì ba vẫn dùng CHUNG phần lồng đó. Cần bản sao hoàn toàn độc lập thì dùng structuredClone(a).

JSON là định dạng text để biểu diễn dữ liệu - trông gần giống object/mảng nhưng khoá phải nháy đôi và không chứa hàm. JSON.stringify đổi object → chuỗi; JSON.parse đổi chuỗi → object. Đây là cách lưu vào localStorage hay gửi qua mạng (API):

object ↔ chuỗi JSON

const sv = { ten: "Lan", diem: [8, 9] };

const s = JSON.stringify(sv);   // chuoi: {"ten":"Lan","diem":[8,9]}
const lai = JSON.parse(s);      // object tro lai

console.log(lai.diem[1]);       // 9

Kết quả khi chạy

9
  • JSON.stringify (object → chuỗi) ↔ JSON.parse (chuỗi → object).
  • Khoá JSON phải nháy đôi; KHÔNG chứa hàm/undefined (bị bỏ qua).
  • Dùng cho API, localStorage, file cấu hình.

Tiếp theo

Giờ bạn xử lý được dữ liệu trong bộ nhớ. Bài sau - “Class & prototype” - trả lời câu hỏi tự nhiên tiếp theo: khi cần nhiều object cùng hình dạng (cùng thuộc tính, cùng method) thì làm sao khỏi viết tay từng cái? Và ở bản chất, class của JavaScript là gì.

Câu hỏi thường gặp

map biến đổi TỪNG phần tử → mảng mới CÙNG độ dài. filter giữ phần tử thoả điều kiện → mảng mới ngắn hơn/bằng. reduce gộp cả mảng về MỘT giá trị (mang theo acc). Cả ba đều nhận một callback (hàm hạng nhất, bài 4) và KHÔNG sửa mảng gốc.

Nên LUÔN truyền init (đối số thứ 2). Nếu không có init mà mảng rỗng, JS báo lỗi "Reduce of empty array with no initial value". Có init thì mảng rỗng trả về init - code an toàn và dễ đọc hơn.

Là cú pháp lấy nhanh giá trị ra khỏi mảng/object. Vd lấy field của object hoặc phần tử của mảng vào biến chỉ trong một dòng. Rất hay dùng cho tham số hàm và props của component.

spread TRẢI các phần tử ra để sao chép & gộp mảng/object (lúc tạo hoặc gọi hàm). rest dùng CÙNG ký hiệu ... nhưng ngược vai: GOM phần còn lại lại (lúc nhận - vd phần tử còn lại của mảng, hay các đối số dư của hàm).

NÔNG (shallow). Nó sao chép một lớp; nếu bên trong còn mảng/object lồng nhau thì bản sao vẫn dùng CHUNG tham chiếu với bản gốc cho phần lồng đó. Muốn sao chép sâu, dùng structuredClone(x) hoặc xử lý từng lớp.

JSON là một ĐỊNH DẠNG TEXT: key bắt buộc nháy đôi, chỉ chứa string/number/boolean/null/array/object - KHÔNG có hàm, undefined hay comment. JSON.stringify sẽ bỏ qua hàm & undefined. Object JS thì linh hoạt hơn (có method, key không cần nháy…).

Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.

Tick những điều em tự tin làm được sau khi học bài này. 0/6

Trả lời vài câu để chắc rằng em đã nắm bài.

Câu 1/3 Điểm: 0

Điểm chung của map, filterfind theo bài là gì?

  1. 1

    map gấp đôi

    Với [1, 2, 3], dùng map tạo [2, 4, 6]. In mảng gốc để xác nhận nó không đổi.

    Hoàn thành khi: map((n) => n * 2) ra [2, 4, 6]; mảng gốc vẫn [1, 2, 3].

  2. 2

    filter số chẵn

    Lọc các số chẵn từ [1, 2, 3, 4, 5, 6].

    Hoàn thành khi: filter((n) => n % 2 === 0) ra [2, 4, 6].

  3. 3

    reduce tổng & tích

    Dùng công cụ ở Bước 3 với [1, 2, 3, 4]: Cộng ra gì, Nhân ra gì? Rồi tự tính tổng [10, 20, 30].

    Hoàn thành khi: Cộng → 10; Nhân → 24; tổng [10, 20, 30] = 60.

  4. 4

    object & lặp

    Tạo object 3 field rồi in từng cặp khoá-giá trị bằng Object.entries.

    Hoàn thành khi: Lặp Object.entries(o) in ra mỗi dòng một cặp key: value.

  5. 5

    spread gộp

    Gộp hai object thành một bằng spread; và sao chép một mảng bằng spread.

    Hoàn thành khi: Object gộp có đủ field của cả hai; mảng sao chép là bản khác tham chiếu với gốc.

  6. 6

    JSON khứ hồi

    stringify một object rồi parse lại. Thử thêm một method vào object - điều gì xảy ra với nó?

    Hoàn thành khi: parse(stringify(o)) cho lại dữ liệu; method (hàm) bị JSON bỏ mất.