في تطوير تطبيقات الويب باستخدام جافاسكريبت، غالبًا ما تحتاج إلى حفظ بيانات المستخدم في المتصفح مؤقتًا أو بشكل دائم؛ مثل إعدادات الثيم (الليلي أو النهاري)، محتويات سلة التسوق، أو بيانات الجلسة المؤقتة. في بيئة تطوير الويب الحديثة، تتعامل عادة مع المتغيرات وكيفية تخزين البيانات في الذاكرة المؤقتة (RAM) أثناء تشغيل السكريبت، لكن هذه البيانات تضيع فورًا بمجرد تحديث الصفحة أو إغلاق المتصفح. لحل هذه المشكلة الجوهرية، يوفر لنا متصفح الويب واجهة برمجة تطبيقات قوية تُعرف باسم Web Storage API.
تنقسم واجهة تخزين الويب إلى جزأين رئيسيين ومستقلين: التخزين المحلي (LocalStorage) والتخزين المؤقت (SessionStorage). في هذا الدليل المتقدم، سنتعمق في كيفية استخدام كل منهما، والفروق الجوهرية بينهما، ومتى يجب عليك استخدام أحدهما دون الآخر بناءً على متطلبات مشروعك البرمجي، مع استعراض الأخطاء الشائعة وطرق تجنبها بأمان.
ما هو الفرق الأساسي بين LocalStorage و SessionStorage؟
يشترك الاثنان في نفس الواجهة البرمجية (API) ونفس الدوال الأساسية تمامًا، والفرق الوحيد يكمن في مدة بقاء البيانات (Lifespan) ونطاق الوصول إليها (Scope). فهم هذا الفرق يحدد بنية وهندسة البيانات في تطبيقك:
- LocalStorage: يحفظ البيانات دون تاريخ انتهاء صلاحية محدد (Persistent Data). تبقى البيانات مخزنة حتى لو أغلقت المتصفح، أو أطفأت جهاز الكمبيوتر، أو أعدت تشغيله. لن تختفي البيانات أبدًا إلا إذا قام المستخدم بمسح ذاكرة التخزين المؤقت للمتصفح يدويًا، أو قام الكود البرمجي بحذفها صراحةً. نطاق الوصول يشمل نفس النطاق (Domain) بغض النظر عن عدد التبويبات المفتوحة.
- SessionStorage: يحفظ البيانات لفترة جلسة التصفح الحالية فقط (Session-based). تنتهي صلاحية البيانات وتُحذف فور إغلاق نافذة المتصفح أو تبويب المتصفح الذي أنشأ تلك البيانات تحديدًا. إذا فتحت نفس الموقع في تبويب جديد، فلن تتمكن من الوصول إلى بيانات التبويب الأول، حيث يُنشئ كل تبويب سياق جلسة منفصل تمامًا.
من الناحية التقنية والأمنية، يخزن كلا النوعين البيانات بصيغة أزواج مفتاح وقيمة (Key-Value Pairs)، ويقبلان النصوص (Strings) فقط كمفاتيح وقيم. الحد الأقصى لحجم التخزين عادة ما يكون حوالي 5 ميجابايت لكل نطاق (Domain)، وهو حجم كافٍ جدًا لتخزين الإعدادات والنصوص والبيانات الخفيفة، ولكن احذر تمامًا من محاولة تخزين ملفات ضخمة أو بيانات حساسة للغاية مثل كلمات المرور الصريحة.
التعامل مع LocalStorage: الحفظ والاسترجاع
يُتيح لنا كائن localStorage تنفيذ العمليات الأساسية الأربع المعروفة بـ CRUD (إنشاء، قراءة، تحديث، حذف) بكل سلاسة. دعونا نستعرض كل دالة مع أمثلة عملية واضحة ومباشرة.
لحفظ بيانات جديدة، نستخدم الدالة setItem(key, value). لنفترض أننا نريد حفظ اسم المستخدم واختياره للوضع الليلي:
// تخزين بيانات بسيطة
localStorage.setItem("username", "أحمد");
localStorage.setItem("isDarkMode", "true");في الكود أعلاه، قمنا بتخزين قيمتين نصيتين. المفتاح (Key) هو "username" والقيمة هي "أحمد". لاسترجاع هذه البيانات لاحقًا، نستخدم الدالة getItem(key) ونمرر إليها اسم المفتاح المطلوب:
// استرجاع البيانات المخزنة
const currentUser = localStorage.getItem("username");
console.log(currentUser); // الناتج: أحمد
const darkModeStatus = localStorage.getItem("isDarkMode");
console.log(darkModeStatus); // الناتج: "true" (نص وليس قيمة منطقية صريحة)لاحظ بدقة أن القيمة المسترجعة دائمًا تكون من نوع نص (String). حتى لو خزنت رقمًا أو قيمة منطقية (Boolean)، سيقوم المتصفح بتحويلها تلقائيًا إلى نص عند التخزين واسترجاعها كنص. سنرى الآن كيف نتعامل مع الكائنات المعقدة (Objects) والمصفوفات (Arrays) لتجنب هذه المشكلة.
التعامل مع الكائنات والمصفوفات عبر JSON
في التطبيقات الواقعية، نادرًا ما نخزن نصوصًا مفردة؛ فغالباً ما نتعامل مع كائنات تحتوي على بيانات متعددة ومترابطة للمستخدم. بما أن التخزين المحلي يقبل النصوص فقط، فإننا نستعين بكائن جافاسكريبت المدمج JSON لتحويل الكائنات إلى نصوص والعكس.
لتحويل كائن إلى نص قبل تخزينه، نستخدم الدالة JSON.stringify()، وعند استرجاعه نحوله مرة أخرى إلى كائن باستخدام الدالة JSON.parse(). إليك مثال عملي متكامل يوضح الطريقة الصحيحة:
// كائن يحتوي على بيانات المستخدم والتفضيلات
const userProfile = {
id: 1042,
name: "سارة خالد",
role: "مطور واجهات",
preferences: {
theme: "dark",
notifications: true
}
};
// 1. تحويل الكائن إلى نص وتخزينه في LocalStorage
localStorage.setItem("userProfile", JSON.stringify(userProfile));
// 2. استرجاع النص وتحويله مرة أخرى إلى كائن جافاسكريبت
const savedDataString = localStorage.getItem("userProfile");
const parsedUser = JSON.parse(savedDataString);
// استخدام البيانات بثقة
console.log(parsedUser.name); // سارة خالد
console.log(parsedUser.preferences.theme); // darkهذه الطريقة ضرورية ومهمة للغاية لأي مطور جافاسكريبت، فتخطي خطوة JSON.stringify سيؤدي حتمًا إلى تخزين النص [object Object] وهو أمر عديم الفائدة تمامًا ويتسبب في تلف البيانات.
حذف وتفريغ البيانات بفعالية
عندما تنتهي الحاجة إلى البيانات، أو عند تسجيل خروج المستخدم من التطبيق، يجب عليك تنظيف الذاكرة المحلية لضمان عدم بقاء بيانات قديمة أو غير صالحة. يوفر لنا التخزين المحلي طريقتين رئيسيتين للقيام بذلك:
- removeItem(key): لحذف عنصر معين ومحدد بناءً على المفتاح الخاص به.
- clear(): لحذف كافة البيانات المخزنة الخاصة بهذا الموقع (Domain) دفعة واحدة.
// حذف مفتاح محدد فقط
localStorage.removeItem("isDarkMode");
// حذف كافة البيانات المخزنة للموقع بالكامل
localStorage.clear();استخدام SessionStorage لجلسات التصفح المؤقتة
كما ذكرنا سابقًا، فإن sessionStorage يشارك تمامًا نفس الدوال البرمجية لـ localStorage (أي setItem، وgetItem، وremoveItem، وclear)، لكن الفرق الجوهري يكمن حصريًا في ديمومة البيانات وعمرها الافتراضي. دعونا نرى مثالًا عمليًا يوضح متى نستخدم التخزين المؤقت بشكل مثالي:
تخيل أنك تبني نموذج إدخال متعدد الخطوات (Multi-step Form)، وتريد حفظ بيانات الخطوة الحالية مؤقتًا بحيث إذا قام المستخدم بالانتقال إلى صفحة أخرى أو تحديث الصفحة داخل نفس التبويب لا تضيع بياناته المدخلة، ولكن إذا أغلق المتصفح تفضل أن يتم تصفير النموذج بالكامل لأسباب تتعلق بالأمان وخصوصية الجلسة:
// تخزين بيانات مؤقتة للخطوة الحالية في النموذج
const formData = {
step: 2,
email: "user@sitegeeky.com",
temporaryInput: "محتوى نموذج غير مكتمل"
};
sessionStorage.setItem("currentFormProgress", JSON.stringify(formData));
// استرجاع البيانات المؤقتة عند الحاجة
const progressData = sessionStorage.getItem("currentFormProgress");
if (progressData) {
const progress = JSON.parse(progressData);
console.log(`أنت في الخطوة رقم: ${progress.step}`);
}إذا قام المستخدم بإغلاق هذا التبويب وفتحه مرة أخرى في نافذة جديدة، ستكون نتيجة استعلام sessionStorage.getItem("currentFormProgress") هي القيمة null، مما يضمن تمامًا عدم بقاء بيانات حساسة أو مؤقتة عالقة في متصفح المستخدم لفترات طويلة قد تهدد الأمان.
الأخطاء الشائعة والقيود التقنية
عند التعامل مع التخزين المحلي والمؤقت، هناك بعض المطبات والأخطاء الشائعة التي يقع فيها المطورون غالبًا، ومن الضروري جداً تجنبها لتصميم تطبيقات ويب مستقرة، سريعة، وآمنة:
-
الاعتماد المفرط ومشاكل الأمان: لا تقم أبداً بتخزين معلومات حساسة للغاية مثل كلمات المرور الصريحة، أو رموز التوثيق المتقدمة (Tokens) التي تفتقر لحماية إضافية، لأن أي سكريبت خبيث أو ثغرة حقن سكربتات (XSS Attack) قادرة تمامًا على قراءة محتويات
localStorageبكل سهولة. -
تجاوز الحد الأقصى للتخزين (QuotaExceededError): إذا حاولت كتابة بيانات حجمها أكبر بكثير من المساحة المتاحة للمتصفح (التي تبلغ عادة حوالي 5 ميجابايت)، سيرمي المتصفح استثناءً يفشل تنفيذ الكود. من الأفضل دائمًا استخدام كتل
try...catchعند كتابة البيانات للتعامل مع هذه الحالة الاستثنائية بأمان تام دون توقف التطبيق. -
عدم التحقق من وجود القيم (Null Checks): إذا حاولت قراءة مفتاح غير موجود أصلاً، ستعيد الدالة القيمة
null. محاولة استدعاء خصائص أو توابع من قيمة تعود كـnull(مثل تنفيذJSON.parse(null)أو قراءة خاصية مباشرة) ستؤدي إلى توقف السكريبت بالكامل عن العمل عبر خطأUncaught TypeError.
إليك مثال برمجي صحيح وسليم تقنيًا للتعامل مع قراءة البيانات مع التحقق السليم من القيم الفارغة:
function getUserTheme() {
const theme = localStorage.getItem("site_theme");
// التحقق الصارم من أن القيمة موجودة وليست null
if (!theme) {
return "light"; // إرجاع القيمة الافتراضية الآمنة
}
return theme;
}
const activeTheme = getUserTheme();
console.log("الثيم النشط حالياً:", activeTheme);خلاصة الدرس
يُعد التخزين المحلي (LocalStorage) والمؤقت (SessionStorage) أداتين أساسيتين ومحوريتين في لغة جافاسكريبت لإدارة حالة البيانات على مستوى المتصفح دون الحاجة المتكررة للخادم في كل عملية بسيطة. تذكر دائمًا القاعدة الذهبية: استخدم LocalStorage للبيانات الدائمة التي ترغب في بقائها لفترات طويلة مثل تفضيلات المستخدم، واستخدم SessionStorage للبيانات المؤقتة والسرية المرتبطة بجلسة تصفح واحدة فقط.
مع الانتباه الجاد لمسألة الأمان وعدم تخزين كلمات المرور، والتحقق المستمر من القيم الفارغة (Null Checks)، واستخدام محولات JSON بشكل صحيح، ستتمكن من بناء تطبيقات ويب سلسة، عالية الأداء، وقوية الاستجابة تلبي احتياجات المستخدمين باحترافية تامة.