Pertanyaan Menyimpan Objek di localStorage HTML5


Saya ingin menyimpan objek JavaScript di HTML5 localStorage, tetapi objek saya tampaknya sedang dikonversi menjadi string.

Saya dapat menyimpan dan mengambil tipe dan larik JavaScript primitif menggunakan localStorage, tetapi objek tidak berfungsi. Haruskah mereka?

Ini kode saya:

var testObject = { 'one': 1, 'two': 2, 'three': 3 };
console.log('typeof testObject: ' + typeof testObject);
console.log('testObject properties:');
for (var prop in testObject) {
    console.log('  ' + prop + ': ' + testObject[prop]);
}

// Put the object into storage
localStorage.setItem('testObject', testObject);

// Retrieve the object from storage
var retrievedObject = localStorage.getItem('testObject');

console.log('typeof retrievedObject: ' + typeof retrievedObject);
console.log('Value of retrievedObject: ' + retrievedObject);

Output konsol

typeof testObject: object
testObject properties:
  one: 1
  two: 2
  three: 3
typeof retrievedObject: string
Value of retrievedObject: [object Object]

Sepertinya saya suka setItem metode mengonversi masukan ke string sebelum menyimpannya.

Saya melihat perilaku ini di Safari, Chrome, dan Firefox, jadi saya menganggap itu kesalahpahaman saya tentang Penyimpanan Web HTML5 spec, bukan bug atau pembatasan khusus browser.

Saya sudah mencoba memahami hal itu klon terstruktur Algoritma yang dijelaskan dalam http://www.w3.org/TR/html5/infrastructure.html. Saya tidak sepenuhnya mengerti apa yang dikatakannya, tapi mungkin masalah saya ada hubungannya dengan properti objek saya yang tidak bisa dihitung (???)

Apakah ada solusi mudah?


Pembaruan: W3C akhirnya mengubah pikiran mereka tentang spesifikasi kloning terstruktur, dan memutuskan untuk mengubah spec agar sesuai dengan implementasi. Lihat https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111. Jadi pertanyaan ini tidak lagi 100% valid, tetapi jawabannya mungkin masih menarik.


2051
2018-01-06 04:05


asal


Jawaban:


Melihat ke apel, Mozilla dan Microsoft dokumentasi, fungsionalitas tampaknya terbatas untuk menangani hanya pasangan kunci / nilai string.

Sebuah solusi dapat dilakukan merangkai objek Anda sebelum menyimpannya, dan kemudian parse ketika Anda mengambilnya:

var testObject = { 'one': 1, 'two': 2, 'three': 3 };

// Put the object into storage
localStorage.setItem('testObject', JSON.stringify(testObject));

// Retrieve the object from storage
var retrievedObject = localStorage.getItem('testObject');

console.log('retrievedObject: ', JSON.parse(retrievedObject));

2650
2018-01-06 04:25



Peningkatan kecil pada a varian:

Storage.prototype.setObject = function(key, value) {
    this.setItem(key, JSON.stringify(value));
}

Storage.prototype.getObject = function(key) {
    var value = this.getItem(key);
    return value && JSON.parse(value);
}

Karena evaluasi sirkuit pendek, getObject() akan segera kembali null jika key tidak dalam Penyimpanan. Itu juga tidak akan melempar a SyntaxError kecuali jika value aku s "" (string kosong; JSON.parse() tidak bisa mengatasinya).


562
2018-06-30 06:45



Anda mungkin merasa berguna untuk memperluas objek Penyimpanan dengan metode praktis ini:

Storage.prototype.setObject = function(key, value) {
    this.setItem(key, JSON.stringify(value));
}

Storage.prototype.getObject = function(key) {
    return JSON.parse(this.getItem(key));
}

Dengan cara ini Anda mendapatkan fungsi yang benar-benar Anda inginkan meskipun di bawah API hanya mendukung string.


195
2018-01-06 04:42



Memperluas objek Storage adalah solusi luar biasa. Untuk API saya, saya telah membuat fasad untuk localStorage dan kemudian memeriksa apakah itu objek atau tidak saat mengatur dan mendapatkan.

var data = {
  set: function(key, value) {
    if (!key || !value) {return;}

    if (typeof value === "object") {
      value = JSON.stringify(value);
    }
    localStorage.setItem(key, value);
  },
  get: function(key) {
    var value = localStorage.getItem(key);

    if (!value) {return;}

    // assume it is an object that has been stringified
    if (value[0] === "{") {
      value = JSON.parse(value);
    }

    return value;
  }
}

64
2018-01-21 18:29



Ada perpustakaan hebat yang membungkus banyak solusi sehingga bahkan mendukung browser yang lebih tua disebut jStorage

Anda dapat mengatur objek

$.jStorage.set(key, value)

Dan ambil dengan mudah

value = $.jStorage.get(key)
value = $.jStorage.get(key, "default value")

52
2017-08-23 03:52



Stringify tidak menyelesaikan semua masalah

Tampaknya jawaban di sini tidak mencakup semua jenis yang mungkin dalam JavaScript, jadi di sini adalah beberapa contoh singkat tentang cara menghadapinya dengan benar:

//Objects and Arrays:
    var obj = {key: "value"};
    localStorage.object = JSON.stringify(obj);  //Will ignore private members
    obj = JSON.parse(localStorage.object);
//Boolean:
    var bool = false;
    localStorage.bool = bool;
    bool = (localStorage.bool === "true");
//Numbers:
    var num = 42;
    localStorage.num = num;
    num = +localStorage.num;    //short for "num = parseFloat(localStorage.num);"
//Dates:
    var date = Date.now();
    localStorage.date = date;
    date = new Date(parseInt(localStorage.date));
//Regular expressions:
    var regex = /^No\.[\d]*$/i;     //usage example: "No.42".match(regex);
    localStorage.regex = regex;
    var components = localStorage.regex.match("^/(.*)/([a-z]*)$");
    regex = new RegExp(components[1], components[2]);
//Functions (not recommended):
    function func(){}
    localStorage.func = func;
    eval( localStorage.func );      //recreates the function with the name "func"

Saya tidak merekomendasikan untuk menyimpan fungsi karena eval() jahat dapat menyebabkan masalah terkait keamanan, optimalisasi, dan debugging.         Secara umum, eval() tidak boleh digunakan dalam kode JavaScript.

Anggota pribadi

Masalah dengan menggunakan JSON.stringify()untuk menyimpan objek adalah, bahwa fungsi ini tidak dapat membuat serial anggota pribadi. Masalah ini dapat diselesaikan dengan menimpa .toString() metode (yang disebut secara implisit ketika menyimpan data dalam penyimpanan web):

//Object with private and public members:
    function MyClass(privateContent, publicContent){
        var privateMember = privateContent || "defaultPrivateValue";
        this.publicMember = publicContent  || "defaultPublicValue";

        this.toString = function(){
            return '{"private": "' + privateMember + '", "public": "' + this.publicMember + '"}';
        };
    }
    MyClass.fromString = function(serialisedString){
        var properties = JSON.parse(serialisedString || "{}");
        return new MyClass( properties.private, properties.public );
    };
//Storing:
    var obj = new MyClass("invisible", "visible");
    localStorage.object = obj;
//Loading:
    obj = MyClass.fromString(localStorage.object);

Referensi melingkar

Masalah lain stringify tidak bisa berurusan dengan referensi melingkar:

var obj = {};
obj["circular"] = obj;
localStorage.object = JSON.stringify(obj);  //Fails

Dalam contoh ini, JSON.stringify() akan melempar a TypeError  "Mengonversi struktur lingkaran ke JSON".         Jika menyimpan referensi melingkar harus didukung, parameter kedua dari JSON.stringify() mungkin digunakan:

var obj = {id: 1, sub: {}};
obj.sub["circular"] = obj;
localStorage.object = JSON.stringify( obj, function( key, value) {
    if( key == 'circular') {
        return "$ref"+value.id+"$";
    } else {
        return value;
    }
});

Namun, menemukan solusi yang efisien untuk menyimpan referensi melingkar sangat tergantung pada tugas-tugas yang perlu dipecahkan, dan memulihkan data semacam itu juga tidak mudah.

Sudah ada beberapa pertanyaan tentang SO berurusan dengan masalah ini: Stringify (mengkonversi ke JSON) objek JavaScript dengan referensi melingkar


50
2017-11-19 09:51



Menggunakan objek JSON untuk penyimpanan lokal:

//SET

var m={name:'Hero',Title:'developer'};
localStorage.setItem('us', JSON.stringify(m));

//MENDAPATKAN

var gm =JSON.parse(localStorage.getItem('us'));
console.log(gm.name);

// Iterasi semua kunci dan nilai penyimpanan lokal

for (var i = 0, len = localStorage.length; i < len; ++i) {
  console.log(localStorage.getItem(localStorage.key(i)));
}

// MENGHAPUS

localStorage.removeItem('us');
delete window.localStorage["us"];

29
2017-11-20 07:06



Secara teori, adalah mungkin untuk menyimpan objek dengan fungsi:

function store (a)
{
  var c = {f: {}, d: {}};
  for (var k in a)
  {
    if (a.hasOwnProperty(k) && typeof a[k] === 'function')
    {
      c.f[k] = encodeURIComponent(a[k]);
    }
  }

  c.d = a;
  var data = JSON.stringify(c);
  window.localStorage.setItem('CODE', data);
}

function restore ()
{
  var data = window.localStorage.getItem('CODE');
  data = JSON.parse(data);
  var b = data.d;

  for (var k in data.f)
  {
    if (data.f.hasOwnProperty(k))
    {
      b[k] = eval("(" + decodeURIComponent(data.f[k]) + ")");
    }
  }

  return b;
}

Namun, serialisasi Fungsi / deserialization tidak dapat diandalkan karena itu tergantung pada implementasi.


27
2018-04-05 21:20



Anda juga dapat mengganti Penyimpanan default setItem(key,value) dan getItem(key) metode untuk menangani objek / array seperti tipe data lainnya. Dengan begitu, Anda cukup menelepon localStorage.setItem(key,value) dan localStorage.getItem(key) seperti biasa.

Saya belum menguji ini secara ekstensif, tetapi tampaknya telah berhasil tanpa masalah untuk proyek kecil yang saya telah main-mainkan.

Storage.prototype._setItem = Storage.prototype.setItem;
Storage.prototype.setItem = function(key, value)
{
  this._setItem(key, JSON.stringify(value));
}

Storage.prototype._getItem = Storage.prototype.getItem;
Storage.prototype.getItem = function(key)
{  
  try
  {
    return JSON.parse(this._getItem(key));
  }
  catch(e)
  {
    return this._getItem(key);
  }
}

22
2018-04-26 13:00



Saya tiba di pos ini setelah menekan pos lain yang telah ditutup sebagai duplikat dari ini - berjudul 'cara menyimpan larik di penyimpanan lokal?'. Yang baik-baik saja kecuali tidak ada thread yang benar-benar memberikan jawaban lengkap tentang bagaimana Anda dapat mempertahankan array di localStorage - namun saya telah berhasil menyusun solusi berdasarkan informasi yang terkandung dalam kedua thread.

Jadi jika ada orang lain yang ingin dapat mendorong / mem-pop / menggeser item dalam array, dan mereka ingin agar array disimpan di localStorage atau memang sessionStorage, di sini Anda pergi:

Storage.prototype.getArray = function(arrayName) {
  var thisArray = [];
  var fetchArrayObject = this.getItem(arrayName);
  if (typeof fetchArrayObject !== 'undefined') {
    if (fetchArrayObject !== null) { thisArray = JSON.parse(fetchArrayObject); }
  }
  return thisArray;
}

Storage.prototype.pushArrayItem = function(arrayName,arrayItem) {
  var existingArray = this.getArray(arrayName);
  existingArray.push(arrayItem);
  this.setItem(arrayName,JSON.stringify(existingArray));
}

Storage.prototype.popArrayItem = function(arrayName) {
  var arrayItem = {};
  var existingArray = this.getArray(arrayName);
  if (existingArray.length > 0) {
    arrayItem = existingArray.pop();
    this.setItem(arrayName,JSON.stringify(existingArray));
  }
  return arrayItem;
}

Storage.prototype.shiftArrayItem = function(arrayName) {
  var arrayItem = {};
  var existingArray = this.getArray(arrayName);
  if (existingArray.length > 0) {
    arrayItem = existingArray.shift();
    this.setItem(arrayName,JSON.stringify(existingArray));
  }
  return arrayItem;
}

Storage.prototype.unshiftArrayItem = function(arrayName,arrayItem) {
  var existingArray = this.getArray(arrayName);
  existingArray.unshift(arrayItem);
  this.setItem(arrayName,JSON.stringify(existingArray));
}

Storage.prototype.deleteArray = function(arrayName) {
  this.removeItem(arrayName);
}

contoh penggunaan - menyimpan string sederhana dalam array localStorage:

localStorage.pushArrayItem('myArray','item one');
localStorage.pushArrayItem('myArray','item two');

contoh penggunaan - menyimpan objek dalam array sessionStorage:

var item1 = {}; item1.name = 'fred'; item1.age = 48;
sessionStorage.pushArrayItem('myArray',item1);

var item2 = {}; item2.name = 'dave'; item2.age = 22;
sessionStorage.pushArrayItem('myArray',item2);

metode umum untuk memanipulasi array:

.pushArrayItem(arrayName,arrayItem); -> adds an element onto end of named array
.unshiftArrayItem(arrayName,arrayItem); -> adds an element onto front of named array
.popArrayItem(arrayName); -> removes & returns last array element
.shiftArrayItem(arrayName); -> removes & returns first array element
.getArray(arrayName); -> returns entire array
.deleteArray(arrayName); -> removes entire array from storage

19
2018-05-07 11:35