Cách sử dụng đối tượng Map JavaScript

Javascript căn bản | by Học Javascript

Trong JavaScript, Map là một cấu trúc dữ liệu mạnh mẽ giúp lưu trữ các cặp key-value một cách có tổ chức và hiệu quả. Không giống như Object, Map hỗ trợ nhiều kiểu dữ liệu làm key và duy trì thứ tự của các phần tử theo thứ tự chèn vào. Để khai thác tối đa sức mạnh của Map, JavaScript cung cấp một loạt phương thức giúp thao tác, duyệt và quản lý dữ liệu một cách linh hoạt.

Trong bài viết này, mình sẽ tìm hiểu chi tiết về các phương thức quan trọng của Map, bao gồm cách thêm, xóa, truy xuất, kiểm tra phần tử, duyệt qua dữ liệu và chuyển đổi giữa Map và các kiểu dữ liệu khác. Qua đó, bạn sẽ thấy được ứng dụng thực tế của Map trong lập trình và hiểu tại sao nó là một lựa chọn tối ưu hơn Object trong nhiều trường hợp.

Giới thiệu về Map trong JavaScript

Trong JavaScript, Map là một kiểu cấu trúc dữ liệu được sử dụng để lưu trữ các cặp key-value (khóa-giá trị). Tương tự như Object, Map cho phép truy xuất dữ liệu bằng key, nhưng nó có một số đặc điểm nổi bật giúp xử lý dữ liệu hiệu quả hơn.

Map là một tập hợp các cặp key-value, trong đó mỗi key là duy nhất. Không giống như Object, Map có thể sử dụng bất kỳ kiểu dữ liệu nào làm key, bao gồm string, number, boolean, object, function, v.v.

Ví dụ về cách tạo và sử dụng Map:

const myMap = new Map();
myMap.set("name", "John");   // Thêm cặp key-value
myMap.set(10, "Number key"); // Key có thể là số
myMap.set(true, "Boolean key"); // Key có thể là boolean

console.log(myMap.get("name")); // Output: "John"
console.log(myMap.get(10)); // Output: "Number key"
console.log(myMap.get(true)); // Output: "Boolean key"

Vai trò của Map trong JavaScript:

  • Lưu trữ dữ liệu có cấu trúc key-value một cách rõ ràng và có thể sử dụng mọi kiểu dữ liệu làm key.
  • Duy trì thứ tự của các phần tử theo thứ tự chèn vào, giúp việc duyệt dữ liệu dễ dàng hơn.
  • Cung cấp các phương thức linh hoạt để thao tác với dữ liệu như thêm, xóa, cập nhật, truy xuất nhanh chóng.

Vai trò của các phương thức trong Map

JavaScript cung cấp nhiều phương thức giúp làm việc với Map hiệu quả. Dưới đây là một số phương thức quan trọng:

Phương thức Mô tả Ví dụ
.set(key, value) Thêm hoặc cập nhật giá trị với một key map.set("age", 25);
.get(key) Lấy giá trị từ key map.get("age"); // 25
.has(key) Kiểm tra key có tồn tại trong Map không map.has("age"); // true
.delete(key) Xóa một cặp key-value map.delete("age");
.clear() Xóa toàn bộ các phần tử trong Map map.clear();
.size Trả về số lượng phần tử trong Map map.size; // 0
.keys() Trả về danh sách các key for (let key of map.keys()) console.log(key);
.values() Trả về danh sách các giá trị for (let value of map.values()) console.log(value);
.entries() Trả về danh sách các cặp key-value for (let entry of map.entries()) console.log(entry);
.forEach(callback) Lặp qua từng phần tử trong Map map.forEach((value, key) => console.log(key, value));

Những phương thức này giúp Map linh hoạt hơn Object, đặc biệt là trong các tình huống cần lưu trữ dữ liệu có key đa dạng hoặc duy trì thứ tự các phần tử.

So sánh Map với Object trong JavaScript

Tiêu chí Map Object
Kiểu dữ liệu của key Có thể là bất kỳ kiểu dữ liệu nào (string, number, object, function,...) Chỉ có thể là string hoặc symbol
Thứ tự lưu trữ Duy trì thứ tự chèn vào Không đảm bảo thứ tự khi thêm/xóa
Hiệu suất truy xuất Nhanh hơn khi có nhiều phần tử Chậm hơn do phải xử lý nhiều thuộc tính kế thừa
Duyệt qua phần tử Dễ dàng với .forEach(), .keys(), .values(), .entries() Cần dùng Object.keys(), Object.values(), Object.entries()
Xóa toàn bộ phần tử map.clear() Duyệt từng key để xóa hoặc gán {} mới
Kiểm tra sự tồn tại của key map.has(key) key in object hoặc object.hasOwnProperty(key)
Dung lượng bộ nhớ Tối ưu hơn trong nhiều trường hợp Tiêu tốn bộ nhớ hơn khi làm việc với nhiều key

Nhóm phương thức thao tác với phần tử Map trong JavaScript

Trong JavaScript, Map cung cấp các phương thức hữu ích để thêm, lấy, kiểm tra, xóa và xóa toàn bộ các phần tử bên trong nó. Dưới đây là cách sử dụng từng phương thức một cách chi tiết.

.set(key, value) – Thêm hoặc cập nhật phần tử

Phương thức .set() được sử dụng để thêm mới một cặp key-value vào Map hoặc cập nhật giá trị của key đã tồn tại.

Cách sử dụng

const myMap = new Map();

// Thêm phần tử vào Map
myMap.set("name", "Alice");
myMap.set("age", 25);
myMap.set(true, "Boolean Key");
myMap.set(100, "Number Key");

console.log(myMap); 
// Map(4) { 'name' => 'Alice', 'age' => 25, true => 'Boolean Key', 100 => 'Number Key' }

// Cập nhật giá trị của key đã tồn tại
myMap.set("age", 30);
console.log(myMap.get("age")); // Output: 30

Đặc điểm:

  • Nếu key chưa tồn tại, .set() sẽ thêm một key-value mới vào Map.
  • Nếu key đã tồn tại, .set() sẽ cập nhật giá trị của key đó.
  • Map có thể sử dụng bất kỳ kiểu dữ liệu nào làm key, bao gồm string, number, boolean, object, function, v.v.

.get(key) – Lấy giá trị theo key

Phương thức .get() được sử dụng để lấy giá trị của một key cụ thể trong Map. Nếu key không tồn tại, nó sẽ trả về undefined.

Cách sử dụng

const myMap = new Map();
myMap.set("username", "john_doe");
myMap.set("email", "[email protected]");

console.log(myMap.get("username")); // Output: "john_doe"
console.log(myMap.get("email")); // Output: "[email protected]"
console.log(myMap.get("phone")); // Output: undefined (key không tồn tại)

Đặc điểm:

  • .get(key) trả về giá trị của key nếu key tồn tại.
  • Nếu key không tồn tại, .get() trả về undefined.

.has(key) – Kiểm tra sự tồn tại của key

Phương thức .has() được sử dụng để kiểm tra xem một key có tồn tại trong Map hay không.

Cách sử dụng

const myMap = new Map();
myMap.set("country", "Vietnam");

console.log(myMap.has("country")); // Output: true
console.log(myMap.has("city")); // Output: false

Đặc điểm:

  • .has(key) trả về true nếu key tồn tại trong Map.
  • .has(key) trả về false nếu key không tồn tại.

Ứng dụng thực tế:

  • Kiểm tra xem một key có tồn tại trước khi lấy giá trị bằng .get(), giúp tránh lỗi khi truy xuất giá trị không tồn tại.

.delete(key) – Xóa một phần tử theo key

Phương thức .delete() được sử dụng để xóa một cặp key-value khỏi Map.

Cách sử dụng

const myMap = new Map();
myMap.set("fruit", "Apple");
myMap.set("drink", "Coffee");

console.log(myMap.has("fruit")); // Output: true

// Xóa phần tử "fruit"
myMap.delete("fruit");

console.log(myMap.has("fruit")); // Output: false
console.log(myMap); // Map(1) { 'drink' => 'Coffee' }

Đặc điểm:

  • .delete(key) trả về true nếu key tồn tại và bị xóa thành công.
  • .delete(key) trả về false nếu key không tồn tại.

.clear() – Xóa toàn bộ phần tử trong Map

Phương thức .clear() được sử dụng để xóa tất cả các phần tử trong Map, làm cho Map trở thành một tập hợp rỗng.

Cách sử dụng

const myMap = new Map();
myMap.set("user", "Alice");
myMap.set("role", "Admin");

console.log(myMap.size); // Output: 2

// Xóa toàn bộ phần tử
myMap.clear();

console.log(myMap.size); // Output: 0
console.log(myMap); // Output: Map(0) {}

Đặc điểm:

  • .clear() xóa tất cả các phần tử trong Map.
  • Sau khi gọi .clear(), kích thước của Map trở về 0.

Ứng dụng thực tế:

  • Sử dụng .clear() khi cần reset dữ liệu trong Map, chẳng hạn như khi đăng xuất tài khoản và muốn xóa thông tin người dùng.
Phương thức Chức năng Trả về
.set(key, value) Thêm hoặc cập nhật key-value trong Map Map (có thể chain)
.get(key) Lấy giá trị của một key Giá trị của key hoặc undefined nếu không tồn tại
.has(key) Kiểm tra key có tồn tại không true hoặc false
.delete(key) Xóa một phần tử theo key true nếu xóa thành công, false nếu key không tồn tại
.clear() Xóa toàn bộ phần tử trong Map Không có giá trị trả về
.size Lấy số lượng phần tử trong Map Số lượng phần tử hiện có

Nhóm phương thức làm việc với kích thước của Map trong JavaScript

Trong JavaScript, Map có một thuộc tính đặc biệt là .size, giúp lấy số lượng cặp key-value hiện có trong Map.

.size – Trả về số lượng phần tử trong Map

Cách sử dụng .size

.size là một thuộc tính của Map, không phải một phương thức, vì vậy nó được sử dụng trực tiếp mà không cần dấu ().

const myMap = new Map();
myMap.set("name", "Alice");
myMap.set("age", 25);
myMap.set("country", "Vietnam");

console.log(myMap.size); // Output: 3

Giải thích:

  • myMap chứa 3 cặp key-value (name, age, country).
  • .size trả về 3, tức là số phần tử hiện có trong Map.

So sánh .size của Map với .length của Array

Thuộc tính Map (.size) Array (.length)
Kiểu dữ liệu Thuộc tính Thuộc tính
Công dụng Trả về số cặp key-value trong Map Trả về số phần tử trong Array
Cách sử dụng map.size array.length
Cập nhật kích thước Tự động cập nhật khi thêm/xóa phần tử Cần cập nhật thủ công trong một số trường hợp
Hiệu suất Tính toán tức thời Có thể yêu cầu tính toán lại trong một số trường hợp

Ví dụ so sánh:

const myArray = [10, 20, 30];
console.log(myArray.length); // Output: 3

const myMap = new Map();
myMap.set(1, "one");
myMap.set(2, "two");
console.log(myMap.size); // Output: 2

Lưu ý:

  • .length của Array có thể thay đổi bằng cách gán giá trị mới (array.length = 0 để xóa toàn bộ mảng).
  • .size của Map không thể gán trực tiếp giá trị mới mà chỉ thay đổi khi thêm hoặc xóa phần tử.

Ví dụ minh họa

Thêm và xóa phần tử, kiểm tra .size

const myMap = new Map();

// Thêm phần tử
myMap.set("user", "John");
myMap.set("email", "[email protected]");
console.log(myMap.size); // Output: 2

// Xóa một phần tử
myMap.delete("email");
console.log(myMap.size); // Output: 1

// Xóa toàn bộ phần tử
myMap.clear();
console.log(myMap.size); // Output: 0

Nhóm phương thức duyệt qua Map trong JavaScript

Trong JavaScript, Map cung cấp nhiều cách khác nhau để duyệt qua các phần tử. Dưới đây là các phương thức phổ biến để lặp qua Map một cách hiệu quả.

.forEach(callback) – Lặp qua từng phần tử trong Map

Cách sử dụng .forEach()

Phương thức .forEach(callback) giúp duyệt qua từng phần tử của Map. Callback function nhận vào ba tham số:

  • value: Giá trị của phần tử trong Map.
  • key: Khóa (key) của phần tử trong Map.
  • map: Đối tượng Map đang được duyệt qua.

Ví dụ minh họa:

const myMap = new Map();
myMap.set("name", "Alice");
myMap.set("age", 25);
myMap.set("country", "Vietnam");

myMap.forEach((value, key) => {
    console.log(`${key}: ${value}`);
});

Output:

name: Alice
age: 25
country: Vietnam

.forEach() giúp duyệt qua Map một cách dễ dàng và không cần quan tâm đến thứ tự lặp.

So sánh với vòng lặp for...of

Tiêu chí .forEach() for...of
Cách duyệt Gọi callback trên từng phần tử Duyệt qua Iterator của Map
Truy cập key-value callback(value, key) Trả về [key, value] dưới dạng mảng
Độ linh hoạt Chỉ có thể dùng trên Map Có thể dùng trên Map, Array, Set, v.v.
Hiệu suất Nhanh hơn khi chỉ cần lặp qua các giá trị Linh hoạt hơn trong nhiều tình huống

Vòng lặp for...of với Map

Cách sử dụng for...of

Vòng lặp for...of giúp duyệt qua các phần tử của Map, với mỗi phần tử được trả về dưới dạng [key, value].

Ví dụ minh họa

const myMap = new Map();
myMap.set("name", "Alice");
myMap.set("age", 25);
myMap.set("country", "Vietnam");

for (const [key, value] of myMap) {
    console.log(`${key}: ${value}`);
}

Output:

name: Alice
age: 25
country: Vietnam

for...of giúp duyệt qua Map một cách trực quan hơn so với .forEach().

.keys() – Lấy danh sách key của Map

Phương thức .keys() trả về một Iterable chứa toàn bộ key trong Map.

Cách sử dụng .keys()

const myMap = new Map([
    ["name", "Alice"],
    ["age", 25],
    ["country", "Vietnam"]
]);

console.log([...myMap.keys()]); // Output: ["name", "age", "country"]

Dùng [...myMap.keys()] để chuyển keys() thành một mảng.

.values() – Lấy danh sách value của Map

Tương tự .keys(), phương thức .values() trả về một Iterable chứa toàn bộ giá trị trong Map.

Cách sử dụng .values()

const myMap = new Map([
    ["name", "Alice"],
    ["age", 25],
    ["country", "Vietnam"]
]);

console.log([...myMap.values()]); // Output: ["Alice", 25, "Vietnam"]

Dùng [...myMap.values()] để chuyển values() thành một mảng.

.entries() – Lấy danh sách cặp key-value dưới dạng mảng

Phương thức .entries() trả về một Iterable chứa các phần tử dưới dạng [key, value].

Cách sử dụng .entries()

const myMap = new Map([
    ["name", "Alice"],
    ["age", 25],
    ["country", "Vietnam"]
]);

console.log([...myMap.entries()]);

Output:

[
    ["name", "Alice"],
    ["age", 25],
    ["country", "Vietnam"]
]

.entries() hữu ích khi muốn chuyển Map thành một mảng của các cặp [key, value].


Tóm tắt cách duyệt qua Map

Phương thức Mô tả Ví dụ sử dụng
.forEach(callback) Duyệt qua từng phần tử trong Map map.forEach((value, key) => console.log(key, value));
for...of Duyệt qua Map theo từng [key, value] for (const [key, value] of map) { console.log(key, value); }
.keys() Lấy danh sách key [...map.keys()]
.values() Lấy danh sách value [...map.values()]
.entries() Lấy danh sách [key, value] [...map.entries()]

Lựa chọn phương pháp duyệt phù hợp sẽ giúp tối ưu hóa hiệu suất và dễ dàng thao tác với dữ liệu trong Map.

5. Chuyển đổi giữa Map và Array

Trong JavaScript, có thể dễ dàng chuyển đổi giữa MapArray bằng cách sử dụng các phương thức có sẵn như Array.from() hoặc new Map(). Việc chuyển đổi này giúp tận dụng những ưu điểm của từng cấu trúc dữ liệu trong các tình huống khác nhau.


5.1. Chuyển từ Map sang Array

Một đối tượng Map có thể được chuyển thành một mảng hai chiều bằng Array.from(map) hoặc toán tử spread [...map].

Ví dụ minh họa

const myMap = new Map([
    ["name", "Alice"],
    ["age", 25],
    ["country", "Vietnam"]
]);

// Cách 1: Dùng Array.from()
const array1 = Array.from(myMap);
console.log(array1);

// Cách 2: Dùng toán tử spread [...]
const array2 = [...myMap];
console.log(array2);

Output:

[
    ["name", "Alice"],
    ["age", 25],
    ["country", "Vietnam"]
]

Cả hai phương thức trên đều chuyển Map thành mảng chứa các cặp [key, value].

Nếu chỉ muốn lấy danh sách key hoặc value, ta có thể dùng .keys().values():

const keysArray = [...myMap.keys()];
console.log(keysArray); // ["name", "age", "country"]

const valuesArray = [...myMap.values()];
console.log(valuesArray); // ["Alice", 25, "Vietnam"]

5.2. Chuyển từ Array sang Map

Một mảng có thể được chuyển thành Map bằng cách sử dụng new Map(array). Điều này đặc biệt hữu ích khi muốn loại bỏ các cặp key-value trùng lặp.

Ví dụ minh họa

const array = [
    ["name", "Alice"],
    ["age", 25],
    ["country", "Vietnam"]
];

const myMap = new Map(array);
console.log(myMap);

Output:

Map(3) {
    "name" => "Alice",
    "age" => 25,
    "country" => "Vietnam"
}

Ứng dụng: Loại bỏ cặp key-value trùng lặp

Khi chuyển đổi từ Array sang Map, các key trùng nhau sẽ tự động bị ghi đè, giúp loại bỏ dữ liệu trùng lặp:

const duplicateArray = [
    ["name", "Alice"],
    ["age", 25],
    ["name", "Bob"] // Key "name" trùng, giá trị bị ghi đè
];

const uniqueMap = new Map(duplicateArray);
console.log(uniqueMap);

Output:

Map(2) {
    "name" => "Bob",  // "Alice" bị ghi đè bởi "Bob"
    "age" => 25
}

Map giúp quản lý dữ liệu theo cặp key-value mà không bị trùng key.


6. Ứng dụng thực tế của các phương thức Map

Các phương thức của Map giúp quản lý dữ liệu hiệu quả hơn so với Object, đặc biệt trong các trường hợp cần đảm bảo thứ tự hoặc làm việc với key có nhiều kiểu dữ liệu.


6.1. Lưu trữ dữ liệu dạng key-value có thứ tự

Không giống như Object, Map duy trì thứ tự của các phần tử khi chúng được thêm vào. Điều này giúp xử lý dữ liệu dễ dàng hơn.

Ví dụ: Lưu trữ thông tin người dùng

const userMap = new Map();
userMap.set(1, { name: "Alice", age: 25 });
userMap.set(2, { name: "Bob", age: 30 });
userMap.set(3, { name: "Charlie", age: 22 });

console.log([...userMap.entries()]);

Kết quả sẽ giữ đúng thứ tự của các phần tử được thêm vào.


6.2. Tạo bộ nhớ đệm (caching) cho dữ liệu

Một ứng dụng quan trọng của Map là làm bộ nhớ đệm (cache) để tối ưu hóa hiệu suất, đặc biệt trong các ứng dụng web.

Ví dụ: Cache dữ liệu người dùng

const userCache = new Map();

function getUser(id) {
    if (userCache.has(id)) {
        console.log("Lấy từ cache:", userCache.get(id));
        return userCache.get(id);
    }

    // Giả sử gọi API lấy dữ liệu người dùng
    const userData = { id, name: `User ${id}`, age: 20 + id };
    userCache.set(id, userData);
    console.log("Thêm vào cache:", userData);
    return userData;
}

// Gọi hàm 2 lần với cùng ID
getUser(1);
getUser(1);

Kết quả:

Thêm vào cache: { id: 1, name: 'User 1', age: 21 }
Lấy từ cache: { id: 1, name: 'User 1', age: 21 }

Lợi ích: Hạn chế gọi API nhiều lần cho cùng một dữ liệu.


6.3. Sử dụng Map trong các thuật toán tìm kiếm nhanh

Nhờ phương thức .has(), Map có thể được sử dụng để kiểm tra dữ liệu nhanh hơn Object.

Ví dụ: Kiểm tra số lần xuất hiện của từ trong một văn bản

const wordCount = new Map();
const text = "apple banana apple orange banana apple";

text.split(" ").forEach(word => {
    wordCount.set(word, (wordCount.get(word) || 0) + 1);
});

console.log(wordCount);

Output:

Map(3) {
    "apple" => 3,
    "banana" => 2,
    "orange" => 1
}

Lợi ích: Map giúp truy xuất dữ liệu nhanh chóng mà không cần duyệt qua toàn bộ danh sách.


6.4. Quản lý danh sách động với nhiều kiểu key khác nhau

Không giống như Object, Map hỗ trợ nhiều kiểu key như number, boolean, function, object.

Ví dụ: Dùng object làm key

const user1 = { id: 1, name: "Alice" };
const user2 = { id: 2, name: "Bob" };

const userScores = new Map();
userScores.set(user1, 95);
userScores.set(user2, 88);

console.log(userScores.get(user1)); // 95

Map có thể dùng object làm key, điều mà Object không thể làm trực tiếp.

Kết bài

Map trong JavaScript là một cấu trúc dữ liệu mạnh mẽ, cung cấp nhiều phương thức hữu ích giúp thao tác với dữ liệu dạng cặp key-value một cách linh hoạt và hiệu quả. So với Object, Map có nhiều ưu điểm như hỗ trợ nhiều kiểu dữ liệu làm key, bảo toàn thứ tự phần tử, và có hiệu suất tìm kiếm tốt hơn trong nhiều trường hợp.

Việc sử dụng các phương thức như .set(), .get(), .has(), .delete(), .size(), cũng như các cách duyệt và chuyển đổi giữa MapArray giúp lập trình viên dễ dàng thao tác với dữ liệu. Trong thực tế, Map được ứng dụng rộng rãi trong việc lưu trữ cấu hình, caching dữ liệu, quản lý danh sách động, và tối ưu thuật toán tìm kiếm.

Hiểu rõ về Map và biết cách tận dụng các phương thức của nó sẽ giúp bạn viết mã nguồn sạch hơn, tối ưu hơn và dễ bảo trì hơn. Nếu bạn cần một cấu trúc dữ liệu linh hoạt để quản lý dữ liệu dạng cặp key-value, Map chính là một lựa chọn tuyệt vời trong JavaScript!

Bài viết liên quan

  • 2