Đối tượng `Map`
Bài viết này giải thích về đối tượng Map.
Chúng tôi sẽ giải thích từng bước, từ các thao tác cơ bản đến các ví dụ thực tế hữu ích trong các tình huống hàng ngày.
YouTube Video
Đối tượng Map
Map là một bộ sưu tập lưu trữ các cặp khóa-giá trị. Nó giống như một đối tượng, nhưng khác ở chỗ bất kỳ kiểu nào, chẳng hạn như đối tượng, hàm hoặc kiểu nguyên thủy, đều có thể được sử dụng làm khóa và thứ tự chèn được giữ nguyên.
Cơ bản về Map
Trước tiên, hãy xem cách tạo một Map và thực hiện các thao tác cơ bản.
Đoạn mã sau là một ví dụ tối giản tạo một map rỗng, thêm các khóa và lấy giá trị.
1// Create an empty Map and add key-value pairs
2const m = new Map();
3m.set('a', 1);
4m.set('b', 2);
5
6console.log(m.get('a')); // 1
7console.log(m.size); // 2
- Trong đoạn mã này, bạn có thể thêm phần tử bằng
set, lấy giá trị bằnggetvà kiểm tra số lượng phần tử với thuộc tínhsize. Mapgiữ nguyên thứ tự chèn, phù hợp cho các xử lý phụ thuộc vào thứ tự.
Cách hoạt động của set, get, has, và delete
Dưới đây là các ví dụ về thao tác đọc, ghi, kiểm tra tồn tại và xoá điển hình.
Với đoạn mã sau, bạn có thể kiểm tra giá trị trả về và tác động của từng phương thức.
1// Demonstrate set, get, has, and delete
2const m2 = new Map();
3m2.set('x', 10);
4console.log(m2.has('x')); // true
5console.log(m2.get('y')); // undefined
6
7m2.delete('x');
8console.log(m2.has('x')); // false
9
10// set returns the map itself, allowing method chaining
11m2.set('a', 1).set('b', 2);
12console.log(m2); // Map { 'a' => 1, 'b' => 2 }
gettrả vềundefinednếu khóa không tồn tại.haskiểm tra sự tồn tại của một khóa, còndeletexóa một khóa.- Ngoài ra, vì
settrả về chính map nên có thể sử dụng phương pháp nối chuỗi (chaining).
Bất kỳ kiểu dữ liệu nào cũng có thể dùng làm khóa (sử dụng đối tượng làm khóa)
Một trong những ưu điểm chính của Map là bạn có thể sử dụng các đối tượng trực tiếp làm khóa.
Ví dụ sau cho thấy cách liên kết giá trị trong Map sử dụng đối tượng làm khóa.
1// Use objects as keys in a Map
2const keyObj = { id: 1 };
3const keyFunc = () => {};
4const objMap = new Map();
5
6// Another object with the same content but a different reference
7const anotherKeyObj = { id: 1 };
8
9objMap.set(keyObj, 'objectValue');
10objMap.set(keyFunc, 'functionValue');
11objMap.set(anotherKeyObj, 'anotherValue');
12
13console.log(objMap.get(keyObj)); // 'objectValue'
14console.log(objMap.get(keyFunc)); // 'functionValue'
15console.log(objMap.get(anotherKeyObj)); // 'anotherValue'
- Khi sử dụng đối tượng làm khóa, điều quan trọng là chúng phải có cùng tham chiếu. Ngay cả khi nội dung giống nhau, các đối tượng có tham chiếu khác nhau vẫn được coi là khác và không phải là cùng một khóa.
Lặp qua (Iteration)
Map giữ thứ tự chèn nên thường được sử dụng để lặp qua.
Dưới đây, chúng tôi sẽ chỉ cách sử dụng for...of, forEach và các phương thức keys(), values() và entries().
1// Iterating a Map with for...of and forEach
2const iterMap = new Map([['a', 1], ['b', 2], ['c', 3]]);
3
4// for...of over entries (default)
5for (const [key, value] of iterMap) {
6 console.log(key, value);
7}
8
9// forEach callback
10iterMap.forEach((value, key) => {
11 console.log(key, value);
12});
13
14// keys() and values()
15console.log([...iterMap.keys()]); // ['a','b','c']
16console.log([...iterMap.values()]); // [1,2,3]
entries()trả về một mảng các cặp[key, value], có thể chuyển thành mảng bằng cú pháp spread. Lưu ý rằng hàm callback củaforEachnhận các tham số theo thứ tựvalue, key.
Chuyển đổi giữa Map và Object
Bạn có thể chuyển đổi một object hiện có thành Map, hoặc chuyển Map thành object thông thường hoặc mảng.
1// Convert between Map and Object / Array
2const obj = { a: 1, b: 2 };
3const mapFromObj = new Map(Object.entries(obj)); // Object -> Map
4console.log(mapFromObj.get('a')); // 1
5
6const objFromMap = Object.fromEntries(mapFromObj); // Map -> Object
7console.log(objFromMap); // { a: 1, b: 2 }
8
9const arrayFromMap = [...mapFromObj]; // Map -> Array of [key, value]
10console.log(arrayFromMap); // [['a',1], ['b',2]]
- Sử dụng
Object.entriesvàObject.fromEntriesgiúp việc chuyển đổi dễ dàng. Tuy nhiên, do khóa của object chỉ là chuỗi hoặc symbol nên khi chuyển đổi về object, các khóa không phải chuỗi sẽ bị mất.
Mẫu thực tế: Đếm tần suất (Count Map)
Khi đếm tần suất các phần tử trong một mảng, việc sử dụng Map giúp quá trình này trở nên đơn giản hơn.
Đoạn mã sau đây là ví dụ sử dụng map để đếm tần suất chuỗi trong mảng và sắp xếp chúng.
1// Count frequencies with Map
2const arr = ['apple','banana','apple','orange','banana','apple'];
3const freq = new Map();
4
5for (const item of arr) {
6 freq.set(item, (freq.get(item) || 0) + 1);
7}
8
9console.log([...freq.entries()]); // [['apple',3], ['banana',2], ['orange',1]]
- Sử dụng
Mapgiúp việc kiểm tra sự tồn tại và cập nhật trở nên dễ dàng hơn. Điều này cũng có thể thực hiện với object, nhưngMapsẽ trực quan hơn khi làm việc với các khóa bất kỳ.
Lưu ý về Map và JSON.stringify (tuần tự hóa dữ liệu)
JSON.stringify không thể tuần tự hóa trực tiếp một Map. Nếu bạn cần lưu một Map, bạn phải chuyển đổi nó trước.
Ví dụ sau đây cho thấy cách chuyển đổi một Map thành mảng trước khi biến nó thành JSON và cách khôi phục lại.
1// Serialize and deserialize a Map
2const m3 = new Map([['x', 1], ['y', 2]]);
3const json = JSON.stringify([...m3]); // convert to array first
4console.log(json); // '[["x",1],["y",2]]'
5
6const restored = new Map(JSON.parse(json));
7console.log(restored.get('x')); // 1
- Các Map cần lưu trữ hoặc truyền đi nên được chuyển thành mảng trước khi tuần tự hóa. Khi khôi phục, sử dụng
JSON.parseđể chuyển thành mảng, sau đó đổi lại thành Map.
Giới thiệu về WeakMap và cách sử dụng
WeakMap khác ở chỗ các khóa của nó được tham chiếu yếu (có thể bị thu gom bộ nhớ).
Nó hữu ích để giữ bộ nhớ cache hoặc siêu dữ liệu với đối tượng làm khóa, tự động giải phóng khi đối tượng khóa bị thu gom bộ nhớ.
1// WeakMap for metadata tied to object lifecycle
2const wm = new WeakMap();
3let obj = {};
4wm.set(obj, { meta: 'info' });
5console.log(wm.get(obj)); // { meta: 'info' }
6
7obj = null; // now the object can be GC'd and its entry removed from WeakMap
WeakMapkhông thể lặp qua hoặc kiểm tra kích thước, nhưng rất hữu ích để ngăn chặn rò rỉ bộ nhớ.
Tóm tắt
Map là một bộ sưu tập tiện lợi, khác với object ở chỗ cho phép mọi kiểu dữ liệu làm khóa và giữ thứ tự chèn. Bằng cách hiểu từ thao tác cơ bản đến nâng cao, bạn có thể quản lý dữ liệu linh hoạt và trực quan hơn. Bằng cách sử dụng Object và Map một cách phù hợp tùy từng trường hợp, bạn có thể nâng cao đáng kể tính rõ ràng và khả năng đọc của mã.
Bạn có thể làm theo bài viết trên bằng cách sử dụng Visual Studio Code trên kênh YouTube của chúng tôi. Vui lòng ghé thăm kênh YouTube.