JavaScript - Đối tượng WeakMap

Xin chào, các nhà phát triển JavaScript tương lai! Hôm nay, chúng ta sẽ cùng khám phá một phần thú vị và đôi khi有点神秘的 của JavaScript: đối tượng WeakMap. Đừng lo lắng nếu bạn mới bắt đầu lập trình; tôi sẽ hướng dẫn bạn từng bước qua khái niệm này, giống như tôi đã làm cho hàng trăm sinh viên trong những năm dạy học của mình. Vậy, hãy lấy một tách cà phê (hoặc trà, nếu đó là sở thích của bạn), và cùng nhau bắt đầu cuộc phiêu lưu với WeakMap nhé!

JavaScript - WeakMap

WeakMap là gì?

Trước khi chúng ta nhảy vào chi tiết, hãy hiểu WeakMap là gì. Hãy tưởng tượng bạn có một chiếc hộp ma thuật nơi bạn có thể cất giữ đồ chơi của mình, nhưng chiếc hộp này có một số tính chất đặc biệt. Nó chỉ chấp nhận các đối tượng làm khóa (không phải chuỗi hoặc số!), và nó có một thói quen kỳ lạ là quên đi các đồ chơi nếu bạn ngừng chơi chúng một thời gian. Đó chính là WeakMap trong JavaScript - một bộ sưu tập chỉ có thể sử dụng các đối tượng làm khóa và không ngăn cản các đối tượng đó bị thu hồi rác khi chúng không còn cần thiết ở nơi khác trong chương trình của bạn.

Cú pháp

Hãy nhìn cách chúng ta tạo và sử dụng một WeakMap:

let myWeakMap = new WeakMap();

Đơn giản phải không? Chỉ cần gọi new WeakMap(), và voilà, bạn đã có chiếc hộp ma thuật sẵn sàng để sử dụng!

Thuộc tính của WeakMap

Hiện tại, bạn có thể đang nghĩ, "Tuyệt vời! Tôi có thể truy cập những thuộc tính nào trên WeakMap này?" Well, đây là một sự thật thú vị: WeakMaps không có bất kỳ thuộc tính có thể đếm được nào. Nó giống như chiếc hộp ma thuật không muốn tiết lộ bí mật của mình dễ dàng. Nhưng đừng lo lắng, chúng ta có các phương thức để tương tác với nó!

Phương thức của WeakMap

WeakMaps có một bộ phương thức nhỏ nhưng mạnh mẽ. Hãy nhìn chúng trong bảng sau:

Phương thức Mô tả
set(key, value) Thêm một phần tử mới với khóa và giá trị xác định
get(key) Trả về giá trị liên quan đến khóa xác định
has(key) Trả về một boolean chỉ ra liệu có phần tử với khóa xác định tồn tại hay không
delete(key) Xóa phần tử xác định khỏi WeakMap

Hãy cùng xem các phương thức này trong hành động!

set(key, value)

let obj1 = {};
let obj2 = {};

let myWeakMap = new WeakMap();
myWeakMap.set(obj1, "Hello");
myWeakMap.set(obj2, "World");

Trong ví dụ này, chúng ta đang thêm hai cặp khóa-giá trị vào WeakMap của mình. Lưu ý cách chúng ta sử dụng các đối tượng (obj1obj2) làm khóa. Nếu chúng ta cố gắng sử dụng một chuỗi hoặc số làm khóa, JavaScript sẽ nhanh chóng抛出一个错误 hơn bạn có thể nói "WeakMap"!

get(key)

console.log(myWeakMap.get(obj1)); // Output: "Hello"
console.log(myWeakMap.get(obj2)); // Output: "World"

Tại đây, chúng ta đang lấy các giá trị liên quan đến các khóa đối tượng của mình. Nó giống như hỏi chiếc hộp ma thuật, "Hey, tôi đã cất gì trong này với khóa này?"

has(key)

console.log(myWeakMap.has(obj1)); // Output: true
console.log(myWeakMap.has({}));   // Output: false

Phương thức has giống như một bảo vệ tại câu lạc bộ. Nó kiểm tra xem một khóa đối tượng cụ thể có trong WeakMap của chúng ta hay không. Trong trường hợp này, obj1 được phép vào, nhưng đối tượng trống {} bị từ chối tại cửa.

delete(key)

myWeakMap.delete(obj1);
console.log(myWeakMap.has(obj1)); // Output: false

Với delete, chúng ta đang nói với WeakMap, "Tôi không muốn chơi với đồ chơi này nữa." Sau khi xóa, obj1 không còn trong WeakMap của chúng ta nữa.

Constructor WeakMap()

Constructor WeakMap cũng có thể chấp nhận một iterable của các cặp khóa-giá trị. Dưới đây là một ví dụ:

let obj3 = {};
let obj4 = {};

let myWeakMap2 = new WeakMap([
[obj3, "Value 1"],
[obj4, "Value 2"]
]);

console.log(myWeakMap2.get(obj3)); // Output: "Value 1"

Điều này giống như nói với chiếc hộp ma thuật, "Đây là danh sách các đồ chơi và nơi tôi muốn chúng được lưu trữ" ngay từ đầu.

Ví dụ

Bây giờ chúng ta đã bao gồm các nguyên tắc cơ bản, hãy nhìn vào một số ví dụ thực tế nơi WeakMaps có thể hữu ích.

Ví dụ 1: Dữ liệu riêng tư

WeakMaps rất tốt cho việc lưu trữ dữ liệu riêng tư liên quan đến các đối tượng:

let privateData = new WeakMap();

class Person {
constructor(name, age) {
privateData.set(this, { name: name, age: age });
}

getName() {
return privateData.get(this).name;
}

getAge() {
return privateData.get(this).age;
}
}

let john = new Person("John", 30);
console.log(john.getName()); // Output: "John"
console.log(john.getAge());  // Output: 30

Trong ví dụ này, chúng ta đang sử dụng một WeakMap để lưu trữ dữ liệu riêng tư cho lớp Person. Dữ liệu được liên kết với mỗi实例 của Person, nhưng không thể truy cập trực tiếp từ bên ngoài các phương thức lớp.

Ví dụ 2: Lưu trữ cache

WeakMaps có thể được sử dụng để lưu trữ kết quả tính toán mà không gây ra rò rỉ bộ nhớ:

let cache = new WeakMap();

function expensiveOperation(obj) {
if (cache.has(obj)) {
console.log("Returning cached result");
return cache.get(obj);
}

let result = /* ... thực hiện phép toán đắt đỏ ... */;
cache.set(obj, result);
return result;
}

let obj = {};
expensiveOperation(obj); // Thực hiện phép toán
expensiveOperation(obj); // Trả về kết quả lưu trữ cache

Trong ví dụ này, chúng ta đang sử dụng một WeakMap để lưu trữ kết quả của một phép toán đắt đỏ. Nếu phép toán đã được thực hiện trước đó trên một đối tượng cụ thể, chúng ta sẽ trả về kết quả lưu trữ thay vì tính toán lại.

Kết luận

Và thế là bạn đã có nó, các bạn! Chúng ta đã khám phá thế giới bí ẩn của WeakMaps trong JavaScript. Từ yêu cầu khóa đặc biệt đến bản chất thân thiện với thu hồi rác của nó, WeakMaps cung cấp một công cụ mạnh mẽ cho các trường hợp cụ thể trong chương trình JavaScript của bạn.

Nhớ rằng, WeakMaps giống như người bạn kỳ lạ chỉ nhớ mặt người, không nhớ tên, và có xu hướng quên đi những người họ không gặp trong một thời gian. Chúng không phải cho mọi trường hợp, nhưng khi bạn cần chúng, chúng rất quý giá.

Khi bạn tiếp tục hành trình JavaScript của mình, hãy giữ WeakMaps trong bộ công cụ của bạn. Bạn永远不会知道 khi nào bạn có thể cần lưu trữ một số dữ liệu riêng tư hoặc tạo một cache không gây rò rỉ bộ nhớ. Chúc bạn may mắn và WeakMaps của bạn luôn mạnh mẽ trong tinh thần!

Credits: Image by storyset