I'd seperti untuk menyimpan objek JavaScript pada HTML5 localStorage
, tapi saya objek yang tampaknya sedang dikonversi ke string.
Saya dapat menyimpan dan mengambil primitif JavaScript jenis dan array menggunakan localStorage
, tapi benda-benda don't tampaknya bekerja. Harus mereka?
Berikut ini's my kode:
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);
Konsol output
typeof testObject: object
testObject properties:
one: 1
two: 2
three: 3
typeof retrievedObject: string
Value of retrievedObject: [object Object]
Tampak bagi saya seperti setItem
metode ini mengkonversi input string sebelum menyimpannya.
Saya melihat perilaku ini di Safari, Chrome, dan Firefox, jadi saya menganggap itu's my kesalahpahaman HTML5 Web Storage spec, bukan browser-bug tertentu atau pembatasan.
I've mencoba untuk masuk akal dari terstruktur clone algoritma yang dijelaskan dalam http://www.w3.org/TR/html5/infrastructure.html. Saya don't sepenuhnya memahami apa itu's mengatakan, tapi mungkin masalah saya lakukan dengan saya objek's sifat tidak enumerable (???)
Apakah ada solusi yang mudah?
Update: W3C akhirnya berubah pikiran tentang terstruktur-clone spesifikasi, dan memutuskan untuk mengubah spek sesuai dengan implementasi. Lihat https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111. Jadi pertanyaan ini tidak lagi 100% valid, tapi jawabannya masih mungkin menarik.
Melihat Apple, Mozilla dan Mozilla lagi dokumentasi, fungsi tampaknya terbatas untuk menangani string satunya pasangan kunci/nilai.
Solusi dapat stringify objek anda sebelum menyimpannya, dan kemudian mengurai ketika anda mengambil itu:
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));
Perbaikan kecil 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 short-circuit evaluasi, getObject()
akan segera kembali null
jika kunci
bukan di Bagasi. Hal ini juga tidak akan membuang SyntaxError
kecuali jika nilai
lebih ","
(string kosong; JSON.parse()
tidak bisa menangani itu).
Anda mungkin menemukan itu berguna untuk memperpanjang Penyimpanan objek dengan metode ini berguna:
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.
Memperluas Penyimpanan objek adalah solusi yang mengagumkan. Bagi saya API, saya telah menciptakan sebuah fasad untuk localStorage dan kemudian memeriksa apakah itu adalah sebuah objek atau tidak sementara pengaturan 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;
}
}
Tampaknya bahwa jawaban di sini don't mencakup semua jenis yang mungkin dalam JavaScript, jadi di sini adalah beberapa contoh tentang cara untuk berurusan dengan mereka 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 isu-isu mengenai keamanan, optimasi, dan debugging.
Secara umum, eval()
tidak boleh digunakan dalam kode JavaScript.
Masalah dengan menggunakan JSON.stringify()
untuk menyimpan benda-benda adalah, bahwa fungsi ini tidak dapat serialise pribadi anggota.
Masalah ini dapat diselesaikan dengan timpa .toString()
metode (yang disebut secara implisit ketika menyimpan data di web storage):
//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);
Masalah lain stringify
dapat't berurusan dengan yang melingkar referensi:
var obj = {};
obj["circular"] = obj;
localStorage.object = JSON.stringify(obj); //Fails
Dalam contoh ini, JSON.stringify()
akan melempar TypeError
"Mengubah struktur melingkar ke JSON".
Jika menyimpan referensi melingkar harus didukung, parameter kedua dari JSON.stringify()
dapat 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 memulihkan data tersebut tidak sepele baik.
Sudah ada beberapa pertanyaan SEHINGGA berurusan dengan masalah ini: https://stackoverflow.com/questions/10392293/stringify-javascript-object-with-circular-reference/12659424#12659424
Ada perpustakaan besar 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")
Dalam teori, itu adalah mungkin untuk menyimpan benda-benda 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, Fungsi serialisasi/deserialization tidak dapat diandalkan karena ini adalah implementasi tergantung.
Saya tiba di posting ini setelah memukul di pos lain yang telah ditutup sebagai duplikat ini berjudul 'bagaimana untuk menyimpan array di localstorage?'. Yang baik-baik saja kecuali benang tidak benar-benar memberikan jawaban penuh bagaimana anda dapat mempertahankan array di localStorage - namun saya telah berhasil untuk kerajinan sebuah solusi yang didasarkan pada informasi yang terkandung dalam kedua benang.
Jadi jika ada orang lain yang ingin bisa push/pop/shift item dalam array, dan mereka ingin array disimpan dalam penyimpanan lokal 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 di localStorage array:
localStorage.pushArrayItem('myArray','item one');
localStorage.pushArrayItem('myArray','item two');
contoh penggunaan - menyimpan benda-benda di sessionStorage array:
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
Merekomendasikan menggunakan abstraksi perpustakaan untuk banyak fitur yang dibahas di sini serta kompatibilitas yang lebih baik. Banyak pilihan:
Anda dapat menggunakan localDataStorage untuk transparan toko javascript jenis data (Array, Boolean, Date, Float, Integer, String dan Objek). Hal ini juga menyediakan data ringan kebingungan, secara otomatis kompres string, memfasilitasi query dengan kunci (nama) serta permintaan (key) nilai, dan membantu untuk menegakkan tersegmentasi ruang penyimpanan dalam domain yang sama dengan awalan tombol.
[DISCLAIMER] saya 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, primitif nilai-nilai yang dihormati.
Anda dapat menggunakan ejson untuk menyimpan benda-benda sebagai string.
EJSON merupakan perpanjangan dari JSON untuk mendukung lebih banyak jenis. Mendukung semua JSON-aman jenis, serta:
- Tanggal (JavaScript
Tanggal
)- Biner (JavaScript
Uint8Array
atau hasil dari EJSON.newBinary)- User-defined jenis (lihat EJSON.addType. Misalnya, Mongo.ObjectID ini dilaksanakan dengan cara ini.)
Semua EJSON serialisasi juga berlaku JSON. Misalnya sebuah objek dengan tanggal dan biner penyangga akan menjadi serial di EJSON sebagai:
{ "d": {"$tanggal": 1358205756553}, "b": {"$biner": "c3VyZS4="} }
Di sini saya localStorage pembungkus menggunakan ejson
https://github.com/UziTech/storage.js
Saya menambahkan beberapa jenis untuk saya wrapper termasuk ekspresi reguler dan fungsi
Pilihan lain akan menggunakan sebuah plugin yang ada.
Misalnya persisto adalah sebuah proyek open source yang menyediakan antarmuka yang mudah untuk localStorage/sessionStorage dan mengotomatiskan ketekunan untuk membentuk bidang (input, tombol radio, dan kotak centang).
(Disclaimer: saya penulis.)
Saya membuat yang lain minimalis bungkus dengan hanya 20 baris kode untuk memungkinkan penggunaan seperti itu harus:
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');
http://rhaboo.org adalah localStorage gula lapisan 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 doesn't menggunakan JSON.stringify/mengurai karena itu akan menjadi tidak akurat dan lambat pada benda-benda besar. Sebaliknya, masing-masing terminal memiliki nilai tersendiri localStorage masuk.
Anda mungkin bisa menebak bahwa saya mungkin memiliki sesuatu untuk dilakukan dengan rhaboo ;-)
Adrian.
Untuk Naskah pengguna bersedia untuk menetapkan dan mendapatkan diketik sifat:
/**
* 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);
}
}
// 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");
Untuk menyimpan objek, anda bisa membuat surat yang dapat anda gunakan untuk mendapatkan sebuah objek dari string ke sebuah objek (yang mungkin tidak masuk akal). Misalnya
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 surat yang digunakan untuk membagi objek, dan's juga sangat eksperimental.
Saya membuat hal yang doesn't memecahkan yang sudah ada Penyimpanan benda-benda, tetapi menciptakan pembungkus sehingga anda dapat melakukan apa yang anda inginkan. Hasilnya adalah normal objek, tidak ada metode, dengan akses seperti objek apapun.
Jika anda ingin 1 localStorage
properti untuk magic:
var prop = ObjectStorage(localStorage, 'prop');
Jika anda membutuhkan beberapa:
var storage = ObjectStorage(localStorage, ['prop', 'more', 'props']);
Segala sesuatu yang anda lakukan untuk prop
, atau benda-benda dalam bagasi
akan secara otomatis disimpan ke localStorage
. Anda're selalu bermain dengan benda 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 dalam dilacak objek akan secara otomatis dilacak.
Yang sangat besar kelemahan: hal ini tergantung pada Objek.mengamati()
sehingga memiliki sangat terbatas dukungan browser. Dan itu doesn't terlihat seperti itu'akan datang untuk Firefox atau Edge dalam waktu dekat.
Berikut beberapa extented versi kode diposting oleh @danott
It'll juga menerapkan hapus nilai dari localstorage dan menunjukkan bagaimana untuk menambahkan Getter dan Setter lapisan jadi bukan
localstorage.setItem(preview, true)
anda dapat menulis
config.preview = true
Oke di sini adalah pergi:
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
Nah anda mungkin strip alias bagian dengan .bind(...)
. Namun saya hanya menaruhnya di sejak itu's benar-benar baik untuk tahu tentang hal ini. Saya tooked saya berjam-jam untuk mencari tahu mengapa sederhana dapatkan = localStorage.getItem;
don't bekerja