Map و Set
مجموعات البيانات الحديثة
10-15 دقيقة
JavaScript الحديثة: Map و Set وبنى البيانات الجديدة
توفّر بنيتا البيانات Map و Set، اللتان ظهرتا مع ES6، طرقًا جديدة وفعّالة للتعامل مع مجموعات البيانات في JavaScript.
Map
Map هي مجموعة من أزواج المفتاح والقيمة، ويمكن أن تكون المفاتيح فيها من أي نوع.
الإنشاء والتعامل الأساسي
// Création d'une Map
const utilisateurs = new Map();
// Ajout d'éléments
utilisateurs.set('alice', { nom: 'Alice', age: 25 });
utilisateurs.set('bob', { nom: 'Bob', age: 30 });
// Récupération de valeurs
console.log(utilisateurs.get('alice')); // { nom: 'Alice', age: 25 }
// Vérification d'existence
console.log(utilisateurs.has('bob')); // true
// Suppression d'éléments
utilisateurs.delete('bob');
// Taille de la Map
console.log(utilisateurs.size); // 1
// Vider la Map
utilisateurs.clear();
التهيئة باستخدام مصفوفة
const contacts = new Map([
['alice', '0123456789'],
['bob', '9876543210']
]);
// Itération sur les entrées
for (const [nom, telephone] of contacts) {
console.log(`${nom}: ${telephone}`);
}
طرق التكرار
const scores = new Map([
['Alice', 95],
['Bob', 80],
['Charlie', 85]
]);
// Itération sur les clés
for (const nom of scores.keys()) {
console.log(nom);
}
// Itération sur les valeurs
for (const score of scores.values()) {
console.log(score);
}
// Itération sur les entrées
scores.forEach((score, nom) => {
console.log(`${nom}: ${score}`);
});
حالات استخدام متقدمة
// Utilisation d'objets comme clés
const objetA = { id: 1 };
const objetB = { id: 2 };
const donnees = new Map();
donnees.set(objetA, 'Données pour A');
donnees.set(objetB, 'Données pour B');
console.log(donnees.get(objetA)); // "Données pour A"
// Conversion Map vers Object
const mapVersObjet = Object.fromEntries(scores);
// Conversion Object vers Map
const objet = { a: 1, b: 2 };
const objetVersMap = new Map(Object.entries(objet));
Set
Set هي مجموعة من القيم الفريدة من أي نوع.
الإنشاء والتعامل الأساسي
// Création d'un Set
const nombres = new Set();
// Ajout d'éléments
nombres.add(1);
nombres.add(2);
nombres.add(2); // Ignoré car déjà présent
console.log(nombres.size); // 2
// Vérification d'existence
console.log(nombres.has(1)); // true
// Suppression d'éléments
nombres.delete(1);
// Vider le Set
nombres.clear();
التهيئة باستخدام مصفوفة
const fruits = new Set(['pomme', 'banane', 'pomme', 'orange']);
console.log(fruits.size); // 3 (pomme n'est compté qu'une fois)
// Conversion Set vers Array
const fruitsUniques = [...fruits];
العمليات على المجموعات
function intersection(setA, setB) {
return new Set([...setA].filter(x => setB.has(x)));
}
function union(setA, setB) {
return new Set([...setA, ...setB]);
}
function difference(setA, setB) {
return new Set([...setA].filter(x => !setB.has(x)));
}
// Exemple d'utilisation
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);
console.log(intersection(setA, setB)); // Set(2) {3, 4}
console.log(union(setA, setB)); // Set(6) {1, 2, 3, 4, 5, 6}
console.log(difference(setA, setB)); // Set(2) {1, 2}
WeakMap و WeakSet
تتيح هذه الإصدارات «الضعيفة» الجمع التلقائي للعناصر غير المشار إليها.
WeakMap
// Création d'une WeakMap
const cache = new WeakMap();
let objet = { id: 1 };
cache.set(objet, 'données associées');
// Si objet est mis à null, les données seront nettoyées
objet = null;
WeakSet
const abonnes = new WeakSet();
let utilisateur = { nom: 'Alice' };
abonnes.add(utilisateur);
console.log(abonnes.has(utilisateur)); // true
// Si utilisateur est mis à null, il sera automatiquement retiré
utilisateur = null;
الأنماط وحالات الاستخدام العملية
ذاكرة تخزين مؤقت باستخدام Map
class Cache {
constructor(ttl = 3600000) { // TTL par défaut : 1 heure
this.cache = new Map();
this.ttl = ttl;
}
set(key, value) {
this.cache.set(key, {
value,
timestamp: Date.now()
});
}
get(key) {
const item = this.cache.get(key);
if (!item) return null;
if (Date.now() - item.timestamp > this.ttl) {
this.cache.delete(key);
return null;
}
return item.value;
}
clear() {
this.cache.clear();
}
}
// Utilisation
const cache = new Cache(5000); // TTL de 5 secondes
cache.set('utilisateur', { id: 1, nom: 'Alice' });
مدير أحداث باستخدام Set
class EventEmitter {
constructor() {
this.listeners = new Map();
}
on(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, new Set());
}
this.listeners.get(event).add(callback);
}
off(event, callback) {
if (this.listeners.has(event)) {
this.listeners.get(event).delete(callback);
}
}
emit(event, data) {
if (this.listeners.has(event)) {
for (const callback of this.listeners.get(event)) {
callback(data);
}
}
}
}
// Utilisation
const emitter = new EventEmitter();
const handler = data => console.log('Données reçues:', data);
emitter.on('data', handler);
emitter.emit('data', { message: 'Hello' });
إدارة الحالة باستخدام Map
class Store {
constructor() {
this.state = new Map();
this.subscribers = new Map();
}
setState(key, value) {
this.state.set(key, value);
if (this.subscribers.has(key)) {
this.subscribers.get(key).forEach(callback =>
callback(value)
);
}
}
getState(key) {
return this.state.get(key);
}
subscribe(key, callback) {
if (!this.subscribers.has(key)) {
this.subscribers.set(key, new Set());
}
this.subscribers.get(key).add(callback);
return () => this.subscribers.get(key).delete(callback);
}
}
// Utilisation
const store = new Store();
const unsubscribe = store.subscribe('compteur', value =>
console.log('Nouveau compteur:', value)
);
store.setState('compteur', 1); // Affiche "Nouveau compteur: 1"
تمارين عملية
- مدير المهام الفريدة
class GestionnaireTaches {
constructor() {
this.taches = new Set();
}
ajouterTache(tache) {
if (this.taches.has(tache)) {
return false;
}
this.taches.add(tache);
return true;
}
supprimerTache(tache) {
return this.taches.delete(tache);
}
getTaches() {
return [...this.taches];
}
}
// Utilisation
const gestionnaire = new GestionnaireTaches();
gestionnaire.ajouterTache('Apprendre JavaScript');
gestionnaire.ajouterTache('Apprendre JavaScript'); // Retourne false
console.log(gestionnaire.getTaches()); // ["Apprendre JavaScript"]
- نظام ذاكرة تخزين مؤقت مع انتهاء الصلاحية
class CacheAvecExpiration {
constructor() {
this.cache = new Map();
}
set(key, value, ttl) {
const expiration = Date.now() + ttl;
this.cache.set(key, { value, expiration });
}
get(key) {
const item = this.cache.get(key);
if (!item) return null;
if (Date.now() > item.expiration) {
this.cache.delete(key);
return null;
}
return item.value;
}
nettoyer() {
const maintenant = Date.now();
for (const [key, item] of this.cache) {
if (maintenant > item.expiration) {
this.cache.delete(key);
}
}
}
}
// Utilisation
const cache = new CacheAvecExpiration();
cache.set('api-data', { results: [] }, 5000); // Expire après 5 secondes
الخلاصة
تُعدّ Map و Set من بنى البيانات الأساسية في JavaScript الحديثة:
- توفّر Map بديلًا أكثر مرونة من الكائنات (Objects) لمجموعات المفتاح والقيمة
- تبسّط Set التعامل مع مجموعات القيم الفريدة
- WeakMap و WeakSet مفيدتان في إدارة الذاكرة
- تسهّل هذه البنى تنفيذ الأنماط الشائعة مثل التخزين المؤقت وإدارة الأحداث
في الدرس القادم، سنطبّق كل هذه المعارف في مشروع كامل لتطبيق ملاحظات.
هل تحتاج إلى مراجعة وحدات ES؟ اطّلع على الدرس السابق حول الوحدات.
التعليقات
التعليقات مدعومة عبر GitHub Discussions
سجّل الدخول باستخدام GitHub للمشاركة في النقاش