Trong JavaScript, Map và Set là hai cấu trúc dữ liệu mạnh mẽ được giới thiệu từ phiên bản ECMAScript 6 (ES6), giúp lập trình viên quản lý và thao tác với dữ liệu một cách linh hoạt hơn. Map cho phép lưu trữ các cặp key-value tương tự như đối tượng nhưng với khả năng hỗ trợ mọi kiểu dữ liệu làm khóa. Set, ngược lại, là một tập hợp các giá trị không trùng lặp, giúp giải quyết vấn đề lọc bỏ phần tử dư thừa. Bài viết này sẽ hướng dẫn bạn từ những khái niệm cơ bản đến những kỹ thuật nâng cao khi làm việc với Map và Set trong JavaScript.

Giới thiệu

Map và Set là hai cấu trúc dữ liệu quan trọng trong JavaScript, cung cấp các phương thức hiệu quả để xử lý và quản lý dữ liệu. Trong bài viết này, chúng ta sẽ tìm hiểu chi tiết về cả hai, từ cơ bản đến nâng cao, kèm theo các ví dụ minh họa.

Map trong JavaScript

Map là một cấu trúc dữ liệu cho phép lưu trữ các cặp key-value, trong đó cả key và value có thể là bất kỳ kiểu dữ liệu nào.

Tạo Map

let myMap = new Map();

// Hoặc tạo Map với các cặp key-value ban đầu
let myMap2 = new Map([
  ['key1', 'value1'],
  ['key2', 'value2']
]);

Các phương thức cơ bản của Map

  • set(key, value): Thêm một cặp key-value mới hoặc cập nhật giá trị nếu key đã tồn tại.
  • get(key): Lấy giá trị của một key.
  • has(key): Kiểm tra xem một key có tồn tại không.
  • delete(key): Xóa một cặp key-value.
  • clear(): Xóa tất cả các phần tử trong Map.
  • size: Trả về số lượng phần tử trong Map.

Ví dụ:

let fruits = new Map();

fruits.set('apple', 5);
fruits.set('banana', 3);
fruits.set('orange', 2);

console.log(fruits.get('banana')); // 3
console.log(fruits.has('grape')); // false
console.log(fruits.size); // 3

fruits.delete('orange');
console.log(fruits.size); // 2

fruits.clear();
console.log(fruits.size); // 0

Duyệt qua Map

let animals = new Map([
  ['dog', 'woof'],
  ['cat', 'meow'],
  ['bird', 'tweet']
]);

// Duyệt qua các key
for (let animal of animals.keys()) {
  console.log(animal);
}

// Duyệt qua các value
for (let sound of animals.values()) {
  console.log(sound);
}

// Duyệt qua các cặp key-value
for (let [animal, sound] of animals.entries()) {
  console.log(`${animal} makes ${sound}`);
}

// Sử dụng forEach
animals.forEach((sound, animal) => {
  console.log(`${animal}: ${sound}`);
});

Ứng dụng nâng cao của Map

Sử dụng Map làm cache:

function memoize(fn) {
  const cache = new Map();
  return function(...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) {
      return cache.get(key);
    }
    const result = fn.apply(this, args);
    cache.set(key, result);
    return result;
  }
}

const expensiveFunction = (a, b) => {
  console.log('Calculating...');
  return a + b;
};

const memoizedFunction = memoize(expensiveFunction);

console.log(memoizedFunction(2, 3)); // Calculating... 5
console.log(memoizedFunction(2, 3)); // 5 (từ cache)

Set trong JavaScript

Set là một cấu trúc dữ liệu cho phép lưu trữ các giá trị duy nhất của bất kỳ kiểu dữ liệu nào.

Tạo Set

let mySet = new Set();

// Hoặc tạo Set với các giá trị ban đầu
let mySet2 = new Set([1, 2, 3, 4, 5]);

Các phương thức cơ bản của Set

  • add(value): Thêm một giá trị mới vào Set.
  • has(value): Kiểm tra xem một giá trị có tồn tại trong Set không.
  • delete(value): Xóa một giá trị khỏi Set.
  • clear(): Xóa tất cả các phần tử trong Set.
  • size: Trả về số lượng phần tử trong Set.

Ví dụ:

let colors = new Set();

colors.add('red');
colors.add('blue');
colors.add('green');
colors.add('blue'); // Không thêm vào vì 'blue' đã tồn tại

console.log(colors.size); // 3
console.log(colors.has('yellow')); // false

colors.delete('green');
console.log(colors.size); // 2

colors.clear();
console.log(colors.size); // 0

Duyệt qua Set

let numbers = new Set([1, 2, 3, 4, 5]);

// Duyệt qua các giá trị
for (let num of numbers) {
  console.log(num);
}

// Sử dụng forEach
numbers.forEach(num => {
  console.log(num);
});

Ứng dụng nâng cao của Set

  1. Loại bỏ các phần tử trùng lặp từ một mảng:
let array = [1, 2, 2, 3, 4, 4, 5];
let uniqueArray = [...new Set(array)];
console.log(uniqueArray); // [1, 2, 3, 4, 5]
  1. Tìm phần tử chung và phần tử khác biệt giữa hai Set:
function intersection(setA, setB) {
  return new Set([...setA].filter(x => setB.has(x)));
}

function difference(setA, setB) {
  return new Set([...setA].filter(x => !setB.has(x)));
}

let setA = new Set([1, 2, 3, 4]);
let setB = new Set([3, 4, 5, 6]);

console.log(intersection(setA, setB)); // Set(2) {3, 4}
console.log(difference(setA, setB)); // Set(2) {1, 2}
  1. Sử dụng Set để kiểm tra anagram:
function areAnagrams(str1, str2) {
  if (str1.length !== str2.length) return false;

  const set1 = new Set(str1.toLowerCase());
  const set2 = new Set(str2.toLowerCase());

  return set1.size === set2.size && 
         [...set1].every(char => set2.has(char));
}

console.log(areAnagrams('listen', 'silent')); // true
console.log(areAnagrams('hello', 'world')); // false

Kết luận

Map và Set là hai cấu trúc dữ liệu quan trọng trong JavaScript, cung cấp các phương thức hiệu quả để xử lý và quản lý dữ liệu. Map thích hợp cho việc lưu trữ các cặp key-value, trong khi Set được sử dụng để lưu trữ các giá trị duy nhất. Cả hai đều có nhiều ứng dụng trong việc tối ưu hóa code và giải quyết các vấn đề phức tạp trong lập trình.