Menyimpan Objek di HTML5 localStorage

2511

Saya ingin menyimpan objek JavaScript dalam HTML5 localStorage, tetapi objek saya tampaknya sedang dikonversi ke string.

Saya dapat menyimpan dan mengambil jenis dan array JavaScript primitif menggunakan localStorage, tetapi objek tampaknya 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 adalah

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

Sepertinya saya seperti setItemmetode ini mengkonversi input ke string sebelum menyimpannya.

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

Saya sudah mencoba memahami algoritma klon terstruktur 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 dapat dihitung (???)

Apakah ada solusi yang mudah?


Pembaruan: W3C akhirnya berubah pikiran tentang spesifikasi terstruktur-klon, dan memutuskan untuk mengubah spesifikasi 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.

Kristopher Johnson
sumber
17
BTW, bacaan Anda tentang "algoritma kloning terstruktur" benar, hanya saja specnya diubah dari nilai string-only menjadi ini setelah implementasinya keluar. Saya mengajukan bug bugzilla.mozilla.org/show_bug.cgi?id=538142 dengan mozilla untuk melacak masalah ini.
Nickolay
2
Ini sepertinya pekerjaan untuk indexedDB ...
markasoftware
1
Bagaimana dengan menyimpan array Objek di localStorage? Saya menghadapi masalah yang sama bahwa itu sedang dikonversi ke string.
Jayant Pareek
1
bisakah Anda hanya membuat serialisasi array? seperti toko dengan JSON yang dirangkaikan kemudian diurai lagi saat memuat?
Brandito
1
Anda dapat menggunakan localDataStorage untuk secara transparan menyimpan tipe data javascript (Array, Boolean, Date, Float, Integer, String dan Object)
Mac

Jawaban:

3172

Melihat dokumentasi Apple , Mozilla dan Mozilla lagi , fungsi tampaknya terbatas untuk menangani pasangan kunci kunci / nilai saja.

Solusinya adalah dengan merapatkan objek Anda sebelum menyimpannya, dan kemudian menguraikannya saat 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));
CMS
sumber
160
amati bahwa metadata apa pun akan dihapus. Anda baru saja mendapatkan objek dengan pasangan kunci-nilai, jadi objek apa pun yang berperilaku perlu dibangun kembali.
oligofren
5
@CMS dapat setItem membuang beberapa pengecualian jika data melebihi kapasitas?
Ashish Negi
3
... berlaku untuk objek dengan referensi melingkar saja, JSON.stringify()memperluas objek yang direferensikan ke "konten" lengkapnya (tersurat tersirat) di objek yang kami rangkai. Lihat: stackoverflow.com/a/12659424/2044940
CodeManX
3
Masalah dengan pendekatan ini adalah masalah kinerja, jika Anda harus menangani array atau objek besar.
Tandai
3
@oligofren benar, tetapi sebagaimana maja menyarankan dengan benar eval () =>, ini adalah salah satu penggunaan yang baik, Anda dapat dengan mudah mengambil kode fungsi => menyimpannya sebagai string dan kemudian eval () kembali :)
jave.web
621

Peningkatan minor pada 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 hubung singkat , getObject()akan segera kembali nulljika keytidak ada di Storage. Hal ini juga tidak akan melempar SyntaxErrorpengecualian jika valueadalah ""(string kosong; JSON.parse()tidak bisa mengatasinya).

Guria
sumber
48
Saya hanya ingin dengan cepat menambahkan penggunaan karena itu tidak segera jelas bagi saya: var userObject = { userId: 24, name: 'Jack Bauer' }; Dan untuk mengaturnya localStorage.setObject('user', userObject); Kemudian mendapatkannya kembali dari penyimpanan userObject = localStorage.getObject('user'); Anda bahkan dapat menyimpan berbagai objek jika Anda mau.
zuallauz
8
Itu hanya ekspresi boolean. Bagian kedua dievaluasi hanya jika yang kiri benar. Dalam hal ini hasil dari seluruh ekspresi akan berasal dari bagian yang benar. Ini adalah teknik populer berdasarkan cara bagaimana ekspresi boolean dievaluasi.
Guria
4
Saya tidak melihat titik variabel lokal dan evaluasi jalan pintas di sini (peningkatan kinerja kecil). Jika keytidak di Penyimpanan Lokal, window.localStorage.getItem(key)mengembalikan null- itu tidak membuang pengecualian "Akses ilegal" - dan JSON.parse(null)mengembalikan nulljuga - itu tidak melempar pengecualian juga, baik di bagian Chromium 21 maupun per ES 5.1 15.12.2 , karena String(null) === "null"yang dapat diartikan sebagai JSON literal .
PointedEars
6
Nilai dalam Penyimpanan Lokal selalu merupakan nilai string primitif. Jadi yang ditangani evaluasi jalan pintas ini adalah ketika seseorang menyimpan ""(string kosong) sebelumnya. Karena itu ketik-convert ke falsedan JSON.parse(""), yang akan membuang SyntaxErrorpengecualian, tidak dipanggil.
PointedEars
2
Ini tidak akan berfungsi di IE8, jadi Anda lebih baik menggunakan fungsi dalam jawaban yang dikonfirmasi jika Anda perlu mendukungnya.
Ezeke
220

Anda mungkin perlu memperluas objek Penyimpanan dengan metode praktis berikut:

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 fungsionalitas yang benar-benar Anda inginkan walaupun di bawah API hanya mendukung string.

Justin Voskuhl
sumber
13
Membungkus pendekatan CMS ke dalam fungsi adalah ide yang bagus, hanya perlu tes fitur: Satu untuk JSON.stringify, satu untuk JSON.parse, dan satu untuk menguji apakah localStorage sebenarnya dapat mengatur dan mengambil objek. Memodifikasi objek host bukanlah ide yang baik; Saya lebih suka melihat ini sebagai metode yang terpisah dan bukan sebagai localStorage.setObject.
Garrett
4
Ini getObject()akan mengeluarkan SyntaxErrorpengecualian jika nilai yang disimpan adalah "", karena JSON.parse()tidak bisa mengatasinya. Lihat edit saya untuk jawaban Guria untuk detailnya.
PointedEars
9
Hanya dua sen saya, tapi saya cukup yakin itu bukan ide yang baik untuk memperluas objek yang disediakan oleh vendor seperti ini.
Sethen
73

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

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;
  }
}
Alex Grande
sumber
1
Ini hampir persis apa yang saya butuhkan. Baru saja menambahkan jika (nilai == null) {return false} sebelum komentar, jika tidak menghasilkan kesalahan ketika memeriksa keberadaan kunci pada localStorage.
Francesco Frapporti
2
Ini sebenarnya cukup keren. Setuju dengan @FrancescoFrapporti Anda perlu jika di sana untuk nilai null. Saya juga menambahkan '|| nilai [0] == "[" 'tes kalau-kalau ada dalam array di sana.
rob_james
Poin bagus, saya akan mengedit ini. Meskipun Anda tidak memerlukan bagian nol, tetapi jika Anda melakukannya saya sarankan tiga ===. Jika Anda menggunakan JSHint atau JSLint Anda akan diperingatkan untuk tidak menggunakan ==.
Alex Grande
3
Dan untuk non-ninja (seperti saya), dapatkah seseorang memberikan contoh penggunaan untuk jawaban ini? Apakah itu data.set('username': 'ifedi', 'fullname': { firstname: 'Ifedi', lastname: 'Okonkwo'});:?
Ifedi Okonkwo
Ya memang! Ketika saya mengatasi keinginan saya untuk diberi makan sendok, saya mengambil kode untuk diuji, dan mendapatkannya. Saya pikir jawaban ini hebat karena 1) Tidak seperti jawaban yang diterima, butuh waktu untuk melakukan pemeriksaan tertentu pada data string, dan 2) Tidak seperti yang berikutnya, ia tidak memperluas objek asli.
Ifedi Okonkwo
64

Stringify tidak menyelesaikan semua masalah

Tampaknya jawaban di sini tidak mencakup semua jenis yang dimungkinkan dalam JavaScript, jadi berikut 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()kejahatan dapat menyebabkan masalah keamanan, pengoptimalan, dan debugging. Secara umum, eval()jangan pernah 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 diatasi dengan menimpa .toString()metode (yang disebut secara implisit saat 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 yang stringifytidak bisa ditangani adalah referensi sirkuler:

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

Dalam contoh ini, JSON.stringify()akan membuang TypeError "Konversi struktur melingkar ke JSON" . Jika menyimpan referensi melingkar harus didukung, parameter kedua 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 diselesaikan, dan mengembalikan data tersebut juga tidak sepele.

Sudah ada beberapa pertanyaan tentang SO yang berurusan dengan masalah ini: Stringify (convert to JSON) objek JavaScript dengan referensi melingkar

maja
sumber
2
Oleh karena itu, dan tidak perlu dikatakan - menyimpan data ke dalam Penyimpanan harus didasarkan pada premis tunggal salinan data sederhana. Bukan Objek hidup.
Roko C. Buljan
51

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

Anda dapat mengatur objek

$.jStorage.set(key, value)

Dan mengambilnya dengan mudah

value = $.jStorage.get(key)
value = $.jStorage.get(key, "default value")
Pemrogram JP
sumber
2
@SuperUberDuper jStorage membutuhkan Prototipe, MooTools, atau jQuery
JProgrammer
28

Secara teori, dimungkinkan 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 / deserialisasi fungsi tidak dapat diandalkan karena bergantung pada implementasi .

aster_x
sumber
1
Serialisasi / deserialisasi fungsi tidak dapat diandalkan karena bergantung pada implementasi . Juga, Anda ingin mengganti c.f[k] = escape(a[k]); dengan Unicode-safe c.f[k] = encodeURIComponent(a[k]);dan eval('b.' + k + ' = ' + unescape(data.f[k]));with b[k] = eval("(" + decodeURIComponent(data.f[k]) + ")");. Tanda kurung diperlukan karena fungsi Anda, jika diserialisasi dengan benar, kemungkinan akan anonim, yang bukan as-adalah valid / Pernyataan / (jadi eval()) akan memberikan SyntaxErrorpengecualian jika tidak).
PointedEars
Dan typeofmerupakan operator , jangan menuliskannya seolah-olah itu sebuah fungsi. Ganti typeof(a[k])dengan typeof a[k].
PointedEars
Selain menerapkan saran saya dan menekankan tidak dapat diandalkannya pendekatan ini, saya telah memperbaiki bug berikut: 1. Tidak semua variabel dideklarasikan. 2. for- intidak difilter untuk properti sendiri. 3. Gaya kode, termasuk referensi, tidak konsisten.
PointedEars
@PointedEars apa perbedaan praktis yang terjadi? spec mengatakan the use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent. saya tidak melihat perbedaan fungsional.
Michael
@Michael Bagian yang Anda kutip dimulai dengan Note *in particular* that …. Tetapi spesifikasi nilai kembali dimulai dengan An implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration.Nilai kembali dapat function foo () {}- dengan asumsi implementasi yang sesuai .
PointedEars
22

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

Jadi, jika ada orang lain yang ingin dapat mendorong / pop / menggeser item dalam sebuah array, dan mereka ingin array itu disimpan di localStorage atau memang sessionStorage, ini dia:

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
Andy Lorenz
sumber
Ini adalah seperangkat metode yang sangat berguna untuk memanipulasi array yang disimpan di localStorage atau sessionStorage, dan layak mendapatkan kredit lebih banyak daripada yang ditarik. @Andy Lorenz Terima kasih telah meluangkan waktu untuk berbagi!
Velojet
6

Anda dapat menggunakan localDataStorage untuk secara transparan menyimpan tipe data javascript (Array, Boolean, Date, Float, Integer, String dan Object). Ini juga memberikan kebingungan data yang ringan, secara otomatis memampatkan string, memfasilitasi kueri menurut kunci (nama) serta kueri menurut nilai (kunci), dan membantu untuk menegakkan penyimpanan bersama tersegmentasi dalam domain yang sama dengan kunci awalan.

[DISCLAIMER] Saya adalah penulis utilitas [/ DISCLAIMER]

Contoh:

localDataStorage.set( 'key1', 'Belgian' )
localDataStorage.set( 'key2', 1200.0047 )
localDataStorage.set( 'key3', true )
localDataStorage.set( 'key4', { 'RSK' : [1,'3',5,'7',9] } )
localDataStorage.set( 'key5', null )

localDataStorage.get( 'key1' )   -->   'Belgian'
localDataStorage.get( 'key2' )   -->   1200.0047
localDataStorage.get( 'key3' )   -->   true
localDataStorage.get( 'key4' )   -->   Object {RSK: Array(5)}
localDataStorage.get( 'key5' )   -->   null

Seperti yang Anda lihat, nilai-nilai primitif dihormati.

Mac
sumber
1
Ini adalah sumber daya yang cemerlang dan hanya apa yang saya butuhkan. Saya sedang melakukan aplikasi Ionic dengan AngularJS di mana saya perlu menyimpan objek javascript tertentu di localStorage dan sampai saat ini saya baru saja melakukan JSON.parse dan JSON.stringify, dan mereka bekerja, tetapi itu sedikit lebih rumit daripada bisa untuk hanya menggunakan utilitas seperti ini. Saya akan mencobanya.
Nmuta
4

Opsi lain adalah menggunakan plugin yang ada.

Misalnya persisto adalah proyek sumber terbuka yang menyediakan antarmuka yang mudah untuk penyimpanan / sesi lokal dan mengotomatiskan kegigihan untuk bidang formulir (input, tombol radio, dan kotak centang).

fitur persisto

(Penafian: Saya penulis.)

mar10
sumber
Masih bekerja pada readme saya, tetapi versi saya tidak memerlukan jQuery, karena tampaknya persisto tidak, tetapi itu memberikan alternatif untuk berurusan dengan objek elemen jQuery. Saya akan menambahkan lebih banyak dalam waktu dekat, karena saya bekerja lebih banyak dengannya, untuk membantu lebih lanjut menangani Objek jQuery yang berbeda dan memelihara hal-hal seperti data persisten. Juga +1 untuk mencoba memberikan solusi yang lebih sederhana! Juga, ia menggunakan semua metode tradisional localStroage; exp: var lsh = new localStorageHelper(); lsh.setItem('bob', 'bill'); Juga termasuk acara.
SpYk3HH
4

Kamu bisa menggunakan ejson untuk menyimpan objek sebagai string.

EJSON adalah perpanjangan dari JSON untuk mendukung lebih banyak tipe. Ini mendukung semua jenis JSON-safe, serta:

Semua serialisasi EJSON juga JSON yang valid. Misalnya objek dengan tanggal dan buffer biner akan diserialisasi dalam EJSON sebagai:

{
  "d": {"$date": 1358205756553},
  "b": {"$binary": "c3VyZS4="}
}

Ini adalah pembungkus localStorage saya menggunakan ejson

https://github.com/UziTech/storage.js

Saya menambahkan beberapa jenis ke pembungkus saya termasuk ekspresi dan fungsi reguler

Tony Brix
sumber
2

Saya membuat pembungkus minimalis lainnya dengan hanya 20 baris kode untuk memungkinkan menggunakannya seperti seharusnya:

localStorage.set('myKey',{a:[1,2,5], b: 'ok'});
localStorage.has('myKey');   // --> true
localStorage.get('myKey');   // --> {a:[1,2,5], b: 'ok'}
localStorage.keys();         // --> ['myKey']
localStorage.remove('myKey');

https://github.com/zevero/simpleWebstorage

zevero
sumber
2

Untuk pengguna naskah yang bersedia menyetel dan mendapatkan properti yang diketik:

/**
 * Silly wrapper to be able to type the storage keys
 */
export class TypedStorage<T> {

    public removeItem(key: keyof T): void {
        localStorage.removeItem(key);
    }

    public getItem<K extends keyof T>(key: K): T[K] | null {
        const data: string | null =  localStorage.getItem(key);
        return JSON.parse(data);
    }

    public setItem<K extends keyof T>(key: K, value: T[K]): void {
        const data: string = JSON.stringify(value);
        localStorage.setItem(key, data);
    }
}

Contoh penggunaan :

// write an interface for the storage
interface MyStore {
   age: number,
   name: string,
   address: {city:string}
}

const storage: TypedStorage<MyStore> = new TypedStorage<MyStore>();

storage.setItem("wrong key", ""); // error unknown key
storage.setItem("age", "hello"); // error, age should be number
storage.setItem("address", {city:"Here"}); // ok

const address: {city:string} = storage.getItem("address");
Flavien Volken
sumber
2

https://github.com/adrianmay/rhaboo adalah lapisan gula penyimpanan lokal yang memungkinkan Anda menulis hal-hal seperti ini:

var store = Rhaboo.persistent('Some name');
store.write('count', store.count ? store.count+1 : 1);
store.write('somethingfancy', {
  one: ['man', 'went'],
  2: 'mow',
  went: [  2, { mow: ['a', 'meadow' ] }, {}  ]
});
store.somethingfancy.went[1].mow.write(1, 'lawn');

Itu tidak menggunakan JSON.stringify / parse karena itu akan tidak akurat dan lambat pada objek besar. Sebagai gantinya, setiap nilai terminal memiliki entri Penyimpanan lokal.

Anda mungkin bisa menebak bahwa saya mungkin ada hubungannya dengan rhaboo.

Adrian May
sumber
1

Berikut beberapa versi kode yang diposkan oleh @danott

Ini juga akan menerapkan nilai hapus dari penyimpanan lokal dan menunjukkan cara menambahkan lapisan Getter dan Setter jadi alih-alih

localstorage.setItem(preview, true)

kamu bisa menulis

config.preview = true

Baiklah, ini dia:

var PT=Storage.prototype

if (typeof PT._setItem >='u') PT._setItem = PT.setItem;
PT.setItem = function(key, value)
{
  if (typeof value >='u')//..ndefined
    this.removeItem(key)
  else
    this._setItem(key, JSON.stringify(value));
}

if (typeof PT._getItem >='u') PT._getItem = PT.getItem;
PT.getItem = function(key)
{  
  var ItemData = this._getItem(key)
  try
  {
    return JSON.parse(ItemData);
  }
  catch(e)
  {
    return ItemData;
  }
}

// Aliases for localStorage.set/getItem 
get =   localStorage.getItem.bind(localStorage)
set =   localStorage.setItem.bind(localStorage)

// Create ConfigWrapperObject
var config = {}

// Helper to create getter & setter
function configCreate(PropToAdd){
    Object.defineProperty( config, PropToAdd, {
      get: function ()      { return (  get(PropToAdd)      ) },
      set: function (val)   {           set(PropToAdd,  val ) }
    })
}
//------------------------------

// Usage Part
// Create properties
configCreate('preview')
configCreate('notification')
//...

// Config Data transfer
//set
config.preview = true

//get
config.preview

// delete
config.preview = undefined

Anda juga dapat menghapus bagian alias dengan .bind(...). Namun saya hanya memasukkannya karena sangat bagus untuk mengetahui hal ini. Saya menghabiskan waktu berjam-jam untuk mencari tahu mengapa cara sederhana get = localStorage.getItem;tidak berhasil

Nadu
sumber
1

Saya membuat sesuatu yang tidak merusak objek Storage yang ada, tetapi membuat pembungkus sehingga Anda dapat melakukan apa yang Anda inginkan. Hasilnya adalah objek normal, tidak ada metode, dengan akses seperti objek apa pun.

Benda yang saya buat.

Jika Anda ingin 1 localStorageproperti menjadi sihir:

var prop = ObjectStorage(localStorage, 'prop');

Jika Anda memerlukan beberapa:

var storage = ObjectStorage(localStorage, ['prop', 'more', 'props']);

Semua yang Anda lakukan prop, atau objek di dalamnya storage akan disimpan secara otomatis localStorage. Anda selalu bermain dengan objek nyata, sehingga Anda dapat melakukan hal-hal seperti ini:

storage.data.list.push('more data');
storage.another.list.splice(1, 2, {another: 'object'});

Dan setiap objek baru di dalam objek yang dilacak akan secara otomatis dilacak.

Kelemahan yang sangat besar: tergantung pada Object.observe()sehingga memiliki dukungan browser yang sangat terbatas. Dan sepertinya tidak akan datang untuk Firefox atau Edge dalam waktu dekat.

Rudie
sumber
1

Anda tidak dapat menyimpan nilai kunci tanpa Format String .

LocalStorage hanya mendukung format String untuk kunci / nilai.

Itu sebabnya Anda harus mengubah data Anda menjadi string apa pun itu Array atau Obyek .

Untuk Menyimpan data di localStorage, pertama-tama ikatlah menggunakan metode JSON.stringify () .

var myObj = [{name:"test", time:"Date 2017-02-03T08:38:04.449Z"}];
localStorage.setItem('item', JSON.stringify(myObj));

Kemudian ketika Anda ingin mengambil data, Anda perlu mengurai String ke Objek lagi.

var getObj = JSON.parse(localStorage.getItem('item'));

Semoga ini bisa membantu.

Moshiur Rahman
sumber
0

Untuk menyimpan objek, Anda bisa membuat huruf yang bisa Anda gunakan untuk mendapatkan objek dari string ke objek (mungkin tidak masuk akal). Sebagai contoh

var obj = {a: "lol", b: "A", c: "hello world"};
function saveObj (key){
    var j = "";
    for(var i in obj){
        j += (i+"|"+obj[i]+"~");
    }
    localStorage.setItem(key, j);
} // Saving Method
function getObj (key){
    var j = {};
    var k = localStorage.getItem(key).split("~");
    for(var l in k){
        var m = k[l].split("|");
        j[m[0]] = m[1];
    }
    return j;
}
saveObj("obj"); // undefined
getObj("obj"); // {a: "lol", b: "A", c: "hello world"}

Teknik ini akan menyebabkan beberapa gangguan jika Anda menggunakan huruf yang Anda gunakan untuk membagi objek, dan itu juga sangat eksperimental.

Seizefire
sumber
0

Saya menemukan cara untuk membuatnya bekerja dengan objek yang memiliki referensi siklik.

Mari kita membuat objek dengan referensi siklik.

obj = {
    L: {
        L: { v: 'lorem' },
        R: { v: 'ipsum' }
    },
    R: {
        L: { v: 'dolor' },
        R: {
            L: { v: 'sit' },
            R: { v: 'amet' }
        }
    }
}
obj.R.L.uncle = obj.L;
obj.R.R.uncle = obj.L;
obj.R.R.L.uncle = obj.R.L;
obj.R.R.R.uncle = obj.R.L;
obj.L.L.uncle = obj.R;
obj.L.R.uncle = obj.R;

Kita tidak dapat melakukannya di JSON.stringifysini, karena referensi melingkar.

bundaran

LOCALSTORAGE.CYCLICJSONmemiliki .stringifydan .parseseperti biasa JSON, tetapi bekerja dengan objek dengan referensi melingkar. ("Karya" yang berarti parse (stringify (obj)) dan obj sama dalam DAN memiliki set identik 'persamaan internal')

Tapi kita bisa menggunakan pintasan:

LOCALSTORAGE.setObject('latinUncles', obj)
recovered = LOCALSTORAGE.getObject('latinUncles')

Maka, recoveredakan "sama" dengan keberatan, dalam arti berikut:

[
obj.L.L.v === recovered.L.L.v,
obj.L.R.v === recovered.L.R.v,
obj.R.L.v === recovered.R.L.v,
obj.R.R.L.v === recovered.R.R.L.v,
obj.R.R.R.v === recovered.R.R.R.v,
obj.R.L.uncle === obj.L,
obj.R.R.uncle === obj.L,
obj.R.R.L.uncle === obj.R.L,
obj.R.R.R.uncle === obj.R.L,
obj.L.L.uncle === obj.R,
obj.L.R.uncle === obj.R,
recovered.R.L.uncle === recovered.L,
recovered.R.R.uncle === recovered.L,
recovered.R.R.L.uncle === recovered.R.L,
recovered.R.R.R.uncle === recovered.R.L,
recovered.L.L.uncle === recovered.R,
recovered.L.R.uncle === recovered.R
]

Berikut ini adalah implementasi dari LOCALSTORAGE

LOCALSTORAGE = (function(){
  "use strict";
  var ignore = [Boolean, Date, Number, RegExp, String];
  function primitive(item){
    if (typeof item === 'object'){
      if (item === null) { return true; }
      for (var i=0; i<ignore.length; i++){
        if (item instanceof ignore[i]) { return true; }
      }
      return false;
    } else {
      return true;
    }
  }
  function infant(value){
    return Array.isArray(value) ? [] : {};
  }
  function decycleIntoForest(object, replacer) {
    if (typeof replacer !== 'function'){
      replacer = function(x){ return x; }
    }
    object = replacer(object);
    if (primitive(object)) return object;
    var objects = [object];
    var forest  = [infant(object)];
    var bucket  = new WeakMap(); // bucket = inverse of objects 
    bucket.set(object, 0);    
    function addToBucket(obj){
      var result = objects.length;
      objects.push(obj);
      bucket.set(obj, result);
      return result;
    }
    function isInBucket(obj){ return bucket.has(obj); }
    function processNode(source, target){
      Object.keys(source).forEach(function(key){
        var value = replacer(source[key]);
        if (primitive(value)){
          target[key] = {value: value};
        } else {
          var ptr;
          if (isInBucket(value)){
            ptr = bucket.get(value);
          } else {
            ptr = addToBucket(value);
            var newTree = infant(value);
            forest.push(newTree);
            processNode(value, newTree);
          }
          target[key] = {pointer: ptr};
        }
      });
    }
    processNode(object, forest[0]);
    return forest;
  };
  function deForestIntoCycle(forest) {
    var objects = [];
    var objectRequested = [];
    var todo = [];
    function processTree(idx) {
      if (idx in objects) return objects[idx];
      if (objectRequested[idx]) return null;
      objectRequested[idx] = true;
      var tree = forest[idx];
      var node = Array.isArray(tree) ? [] : {};
      for (var key in tree) {
        var o = tree[key];
        if ('pointer' in o) {
          var ptr = o.pointer;
          var value = processTree(ptr);
          if (value === null) {
            todo.push({
              node: node,
              key: key,
              idx: ptr
            });
          } else {
            node[key] = value;
          }
        } else {
          if ('value' in o) {
            node[key] = o.value;
          } else {
            throw new Error('unexpected')
          }
        }
      }
      objects[idx] = node;
      return node;
    }
    var result = processTree(0);
    for (var i = 0; i < todo.length; i++) {
      var item = todo[i];
      item.node[item.key] = objects[item.idx];
    }
    return result;
  };
  var console = {
    log: function(x){
      var the = document.getElementById('the');
      the.textContent = the.textContent + '\n' + x;
	},
	delimiter: function(){
      var the = document.getElementById('the');
      the.textContent = the.textContent +
		'\n*******************************************';
	}
  }
  function logCyclicObjectToConsole(root) {
    var cycleFree = decycleIntoForest(root);
    var shown = cycleFree.map(function(tree, idx) {
      return false;
    });
    var indentIncrement = 4;
    function showItem(nodeSlot, indent, label) {
      var leadingSpaces = ' '.repeat(indent);
      var leadingSpacesPlus = ' '.repeat(indent + indentIncrement);
      if (shown[nodeSlot]) {
        console.log(leadingSpaces + label + ' ... see above (object #' + nodeSlot + ')');
      } else {
        console.log(leadingSpaces + label + ' object#' + nodeSlot);
        var tree = cycleFree[nodeSlot];
        shown[nodeSlot] = true;
        Object.keys(tree).forEach(function(key) {
          var entry = tree[key];
          if ('value' in entry) {
            console.log(leadingSpacesPlus + key + ": " + entry.value);
          } else {
            if ('pointer' in entry) {
              showItem(entry.pointer, indent + indentIncrement, key);
            }
          }
        });
      }
    }
	console.delimiter();
    showItem(0, 0, 'root');
  };
  function stringify(obj){
    return JSON.stringify(decycleIntoForest(obj));
  }
  function parse(str){
    return deForestIntoCycle(JSON.parse(str));
  }
  var CYCLICJSON = {
    decycleIntoForest: decycleIntoForest,
    deForestIntoCycle : deForestIntoCycle,
    logCyclicObjectToConsole: logCyclicObjectToConsole,
    stringify : stringify,
    parse : parse
  }
  function setObject(name, object){
    var str = stringify(object);
    localStorage.setItem(name, str);
  }
  function getObject(name){
    var str = localStorage.getItem(name);
    if (str===null) return null;
    return parse(str);
  }
  return {
    CYCLICJSON : CYCLICJSON,
    setObject  : setObject,
    getObject  : getObject
  }
})();
obj = {
	L: {
		L: { v: 'lorem' },
		R: { v: 'ipsum' }
	},
	R: {
		L: { v: 'dolor' },
		R: {
			L: { v: 'sit' },
			R: { v: 'amet' }
		}
	}
}
obj.R.L.uncle = obj.L;
obj.R.R.uncle = obj.L;
obj.R.R.L.uncle = obj.R.L;
obj.R.R.R.uncle = obj.R.L;
obj.L.L.uncle = obj.R;
obj.L.R.uncle = obj.R;

// LOCALSTORAGE.setObject('latinUncles', obj)
// recovered = LOCALSTORAGE.getObject('latinUncles')
// localStorage not available inside fiddle ):
LOCALSTORAGE.CYCLICJSON.logCyclicObjectToConsole(obj)
putIntoLS = LOCALSTORAGE.CYCLICJSON.stringify(obj);
recovered = LOCALSTORAGE.CYCLICJSON.parse(putIntoLS);
LOCALSTORAGE.CYCLICJSON.logCyclicObjectToConsole(recovered);

var the = document.getElementById('the');
the.textContent = the.textContent + '\n\n' +
JSON.stringify(
[
obj.L.L.v === recovered.L.L.v,
obj.L.R.v === recovered.L.R.v,
obj.R.L.v === recovered.R.L.v,
obj.R.R.L.v === recovered.R.R.L.v,
obj.R.R.R.v === recovered.R.R.R.v,
obj.R.L.uncle === obj.L,
obj.R.R.uncle === obj.L,
obj.R.R.L.uncle === obj.R.L,
obj.R.R.R.uncle === obj.R.L,
obj.L.L.uncle === obj.R,
obj.L.R.uncle === obj.R,
recovered.R.L.uncle === recovered.L,
recovered.R.R.uncle === recovered.L,
recovered.R.R.L.uncle === recovered.R.L,
recovered.R.R.R.uncle === recovered.R.L,
recovered.L.L.uncle === recovered.R,
recovered.L.R.uncle === recovered.R
]
)
<pre id='the'></pre>

matematika seperti awan
sumber
-2

localStorage.setItem ('user', JSON.stringify (user));

Lalu untuk mengambilnya dari toko dan mengubahnya menjadi objek lagi:

var user = JSON.parse (localStorage.getItem ('user'));

Jika kita perlu menghapus semua entri toko, kita cukup melakukannya:

localStorage.clear ();

manasa woddeyar manu
sumber
3
Ini pertanyaan berumur 10 tahun. Apakah menurut Anda jawaban Anda menambahkan sesuatu yang belum dicakup oleh jawaban lainnya?
Kristopher Johnson