در این درس میخوانید
تازهکردن صفحه نباید همیشه تنظیمات کوچک کاربر را از بین ببرد. برای نمونه، میتوان انتخاب پوسته را در مرورگر نگه داشت. اما دادهٔ ذخیرهشده ممکن است قدیمی، خراب یا توسط کاربر تغییر کرده باشد؛ آن را معتبر فرض نمیکنیم. در درس هفدهم، تنظیمات ساده را با JSON تبدیل و در localStorage نگه میداریم. این مثال محل نگهداری رمز، کلید خصوصی، اطلاعات پرداخت یا مرجع اعتماد حساب کاربر نیست.
JSON یک قالب متنی است، نه خود شیء JavaScript
JSON.stringify دادهٔ قابل پشتیبانی را به متن تبدیل میکند و JSON.parse از متن معتبر، مقدار میسازد. JSON از کوتیشن دوتایی استفاده میکند و تابع یا comment ندارد. بعضی دادهها هنگام تبدیل تغییر میکنند یا پشتیبانی نمیشوند؛ برای مثال Date معمولاً به متن تاریخ تبدیل میشود، ویژگی با undefined ممکن است حذف شود و BigInt بدون قرارداد تبدیل ویژه میتواند خطا بدهد. رفتوبرگشت JSON روش عمومی کپی همهٔ شیءهای JavaScript نیست.
const preferences = { theme: "dark", fontSize: 18 };
const text = JSON.stringify(preferences);
console.log(typeof text); // string
const restored = JSON.parse(text);
console.log(restored.theme); // dark
console.log(restored === preferences); // falselocalStorage چه چیزی نگه میدارد؟
کلید و مقدار localStorage رشتهاند و داده به مبدأ وب وابسته است؛ تغییر پروتکل، میزبان یا پورت میتواند فضای متفاوتی بدهد. getItem برای کلید موجودنبودن null برمیگرداند. داده معمولاً میان بارگذاریهای صفحه میماند، اما سیاست مرورگر، حالت خصوصی، پاککردن داده یا محدودیت فضا روی آن اثر میگذارند. sessionStorage به نشست صفحه وابسته است و برای نیازهای متفاوتی به کار میرود؛ هیچکدام جای پشتیبان معتبرِ دادهٔ مهم سرور نیستند.
یک قرارداد کوچک و نسخهدار تعریف کنید
const STORAGE_KEY = "darsavand-demo.preferences.v1";
function validPreferences(value) {
return value !== null && typeof value === "object" &&
value.version === 1 &&
(value.theme === "light" || value.theme === "dark") &&
Number.isInteger(value.fontSize) &&
value.fontSize >= 12 && value.fontSize <= 28;
}نسخه کمک میکند تغییر شکل داده در آینده قابل تشخیص باشد. این validator فقط قرارداد همین تنظیمات را میپذیرد؛ همهٔ ویژگیهای ناشناخته را به تنظیمات امنیتی برنامه منتقل نمیکنیم. در پروژهٔ واقعی میتوان مهاجرت نسخه را طراحی کرد، اما شروع ساده این است که دادهٔ ناسازگار را بشناسیم و یک مقدار پیشفرض آگاهانه داشته باشیم. «JSON معتبر» الزاماً به معنای «دادهٔ مناسب برنامه» نیست.
خواندن را با مدیریت خطا انجام دهید
function readPreferences() {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (raw === null) return { state: "empty", value: null };
const parsed = JSON.parse(raw);
if (!validPreferences(parsed)) return { state: "invalid", value: null };
return { state: "ready", value: parsed };
} catch (error) {
return { state: "unavailable-or-invalid", value: null };
}
}
const saved = readPreferences();
const activePreferences = saved.value ?? { version: 1, theme: "light", fontSize: 16 };
console.log(saved.state, activePreferences);این مثال به محیط مرورگر، پروژه یا Node.js نیاز دارد؛ طبق راهنمای درس اجرا کنید.کل دسترسی داخل try قرار گرفته، چون حتی دسترسی به فضای ذخیرهسازی ممکن است با محدودیت محیط خطا بدهد. این نسخه، نبود داده را از دادهٔ ناسازگار جدا میکند و برای خطای دسترسی یا تجزیه، وضعیت مشترکِ قابل نمایش برمیگرداند. در برنامهٔ دقیقتر میتوانید این دو علت را تفکیک کنید. تابع دادهٔ اصلی را خودکار حذف نمیکند؛ پاککردن عمومی localStorage ممکن است تنظیمات نامرتبط سایت را هم از بین ببرد.
ذخیرهٔ ناموفق را موفق نشان ندهید
function savePreferences(value) {
if (!validPreferences(value)) return { ok: false, reason: "invalid" };
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(value));
return { ok: true };
} catch (error) {
return { ok: false, reason: "storage-unavailable" };
}
}
console.log(savePreferences({ version: 1, theme: "dark", fontSize: 18 }));این مثال به محیط مرورگر، پروژه یا Node.js نیاز دارد؛ طبق راهنمای درس اجرا کنید.اگر ذخیره شکست خورد، رابط باید بگوید تنظیم فعلی ممکن است بعد از بستن صفحه نماند. localStorage همگام است؛ نوشتن دادهٔ بزرگ یا نوشتن در هر ضربهٔ صفحهکلید میتواند کار اصلی مرورگر را معطل کند. برای دادهٔ حجیم و جستوجوی محلی پیچیده، IndexedDB و طراحی مناسب را بررسی کنید. تغییر یک کلید در برگهٔ دیگر میتواند storage event ایجاد کند؛ این رویداد معمولاً برای همان سندِ انجامدهندهٔ تغییر صادر نمیشود.
امنیت و اعتماد به داده
اسکریپتهای همان مبدأ میتوانند به localStorage دسترسی داشته باشند. اگر XSS رخ دهد، نگهداری دادهٔ حساس در آن خطر را بیشتر میکند. بنابراین وضعیت «مدیر بودن»، پرداخت موفق یا اجازهٔ دانلود را از آن معتبر نمیدانیم. دادهٔ بازیابیشده را هم پیش از نمایش اعتبارسنجی میکنیم و برای متن از textContent استفاده میکنیم. رمزگذاری با کلیدی که کنار همان کد عمومی مرورگر قرار دارد، بهتنهایی این مشکل اعتماد را حل نمیکند.
تمرین و پاسخ راهنما
بعد از ذخیرهٔ تنظیم صحیح، صفحه را تازه کنید و state برابر ready را ببینید. سپس فقط کلید نمونه را با یک متن JSON نامعتبر تغییر دهید و مطمئن شوید تابع خواندن، برنامه را از کار نمیاندازد. در تمرین دوم، fontSize برابر 40 را برای ذخیره بفرستید؛ پاسخ باید ok برابر false و reason برابر invalid باشد. برای حذف آزمایشی نیز فقط از removeItem روی همین کلید استفاده کنید، نه clear عمومی.
console.log(savePreferences({ version: 1, theme: "dark", fontSize: 40 }));
// { ok: false, reason: "invalid" }
// فقط برای پاککردن دادهٔ همین تمرین:
// localStorage.removeItem(STORAGE_KEY);این مثال به محیط مرورگر، پروژه یا Node.js نیاز دارد؛ طبق راهنمای درس اجرا کنید.پرسشهای مرور
- چرا متن JSON معتبر ممکن است برای برنامه نامعتبر باشد؟
- چرا localStorage را نباید مرجع اجازهٔ کاربر دانست؟
- اگر ذخیرهسازی در دسترس نبود، رابط چه پیامی باید نشان دهد؟
- چرا برای حذف یک تنظیم، clear عمومی انتخاب مناسبی نیست؟
منابع انگلیسی
- MDN — Using the Web Storage API
- https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
- MDN — JSON
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON
- MDN — Window.localStorage
- https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
نمونهٔ تنظیمات برای این مسیر نوشته شده است. در درس بعد، رفتار تابعها و حالتهای مرزی را با آزمون خودکار بررسی میکنیم.
پیشنیاز و محیط اجرای مثالها
درس 17 از ۲۰؛ پیشنیاز: درسهای قبلی مجموعه. مثالها را در پروژهٔ محلی خود و از آدرس HTTP محلی اجرا کنید. کلیدهای نمونه با پیشوند darsavand-demo هستند و دادهٔ غیرحساس آزمایشی نگه میدارند.
پیشرفت روی همین مرورگر ذخیره میشود.