ข้ามไปยังเนื้อหา

JSON and Objects

Web Storage เก็บได้เฉพาะ string เท่านั้น หากคุณส่งอย่างอื่นเข้าไปให้ setItem browser จะแปลงเป็น string ให้อย่างเงียบ ๆ:

localStorage.setItem('demo:num', 42);
console.log(localStorage.getItem('demo:num')); // "42" — a string, not a number
typeof localStorage.getItem('demo:num'); // "string"
localStorage.setItem('demo:bool', true);
console.log(localStorage.getItem('demo:bool')); // "true" — a string, not a boolean
localStorage.setItem('demo:obj', { key: 'value' });
console.log(localStorage.getItem('demo:obj')); // "[object Object]" — useless!

นี่หมายความว่าคุณ ไม่สามารถ เก็บ object, array, number หรือ boolean ได้โดยตรงแล้วคาดหวังว่าจะอ่านกลับมาในชนิดเดิม

แพตเทิร์นมาตรฐานคือ serialise ด้วย JSON.stringify ตอนเขียน และ deserialise ด้วย JSON.parse ตอนอ่าน:

const user = { name: 'Ada', age: 36, admin: false };
// Write
localStorage.setItem('demo:user', JSON.stringify(user));
// Read back
const raw = localStorage.getItem('demo:user');
const restored = raw !== null ? JSON.parse(raw) : null;
console.log(restored.name); // 'Ada'
console.log(restored.age); // 36 (number, not string)
console.log(restored.admin); // false (boolean, not string)

JSON.stringify รองรับ object ซ้อน, array, number, boolean และ null ได้ แต่ ไม่ เก็บรักษาสิ่งเหล่านี้:

  • ค่า undefined (จะถูกละทิ้ง)
  • Function (จะถูกละทิ้ง)
  • object Date (ถูกแปลงเป็น ISO string — ใช้ new Date(str) เพื่อกู้คืน)
  • Map, Set, RegExp, BigInt (ไม่สามารถ serialise เป็น JSON ได้หากไม่มี replacer ที่กำหนดเอง)

แทนที่จะเขียนแพตเทิร์น stringify/parse ซ้ำไปทุกที่ helper เล็ก ๆ ตัวหนึ่งจะช่วยให้โค้ดสะอาด:

function storageGet(key, fallback) {
try {
const raw = localStorage.getItem(key);
return raw !== null ? JSON.parse(raw) : fallback;
} catch {
return fallback; // Guard against corrupt/non-JSON values
}
}
function storageSet(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}

try/catch รอบ ๆ JSON.parse เป็นเรื่องสำคัญ: หากค่าที่เก็บไว้ถูกเขียนโดยโค้ดเก่า (plain string), สคริปต์จาก third-party หรือถูกแก้ไขด้วยมือใน DevTools ค่านั้นอาจไม่ใช่ JSON ที่ถูกต้อง และ JSON.parse จะโยน error

Browser Storage
ตัวเลือกBenefitCost
JSON.stringify/JSON.parseเก็บ object ซ้อนกันหลายชั้นและ array ได้ครบ ใช้ pattern เดียวกันทุกที่ต้อง parse ใหม่ทุกครั้งที่อ่าน เสีย CPU เพิ่มขึ้นตามขนาดข้อมูล
เก็บเป็น string ดิบ (ไม่ stringify)เร็วกว่า ไม่มี overhead ของการ serialiseได้ค่ากลับมาผิดชนิดเสมอ (number/boolean กลายเป็น string) และ object กลายเป็น "[object Object]"
helper storageGet/storageSet แบบ typedโค้ดสั้นลง มี try/catch ป้องกัน corrupt data ในตัวเพิ่ม layer เล็ก ๆ ที่ทีมต้องรู้จักและดูแลรักษา
  • ส่ง object เข้า setItem ตรง ๆ โดยไม่ stringify — ได้ "[object Object]" กลับมา ให้ JSON.stringify ก่อนเขียนเสมอ
  • เรียก JSON.parse โดยไม่มี try/catch — ถ้าค่าที่เก็บไว้ไม่ใช่ JSON ที่ถูกต้อง (ถูกเขียนด้วยมือใน DevTools หรือมาจากโค้ดเวอร์ชันเก่า) แอปจะ crash ทันที
  • คาดหวังว่า Date จะกลับมาเป็น Date object หลัง parseJSON.stringify แปลง Date เป็น ISO string เสมอ ต้องเรียก new Date(str) เองเพื่อกู้คืนชนิดเดิม

💡 ตัวอย่างจากของจริง

Notion / Google Docs — ฟีเจอร์ autosave ฉบับร่างจะ JSON.stringify state ทั้งฟอร์ม (title, blocks, cursor position) แล้วเก็บลง localStorage เป็นระยะ เพื่อกู้คืนงานได้หากแท็บถูกปิดโดยไม่ตั้งใจ

Web app ที่มี dark mode / theme settings — เก็บ object การตั้งค่าทั้งก้อน ({ theme, fontSize, locale }) ไว้ใน key เดียวด้วย JSON.stringify แล้วอ่านกลับมา parse ตอนแอป bootstrap เพื่อ apply ค่าก่อน render หน้าแรก

คุณเก็บ object ของ JavaScript ด้วย localStorage.setItem("x", myObj) โดยไม่ stringify อ่านกลับมาจะได้อะไร?
method ใดที่แปลงค่า JavaScript ให้เป็น JSON string เพื่อเก็บ?
หลังจากเก็บ number ด้วย localStorage.setItem("n", 42) (ไม่ใช้ JSON.stringify) typeof localStorage.getItem("n") คืออะไร?
ทำไมคุณจึงควรครอบ JSON.parse ด้วย try/catch เมื่ออ่านจาก localStorage?