オブジェクトをHTML5 localStorageに保存する


2511

JavaScriptオブジェクトをHTML5に保存したいのですlocalStorageが、オブジェクトが文字列に変換されているようです。

を使用してプリミティブなJavaScriptタイプと配列を保存および取得できますlocalStorageが、オブジェクトが機能していないようです。彼らはすべきですか?

これが私のコードです:

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);

コンソール出力は

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

setItemメソッドは入力を文字列に変換してから保存するように見えます。

この動作はSafari、Chrome、Firefoxで見られるので、ブラウザ固有のバグや制限ではなく、HTML5 Web Storage仕様の誤解だと思います。

http://www.w3.org/TR/html5/infrastructure.htmlで説明されている構造化クローンアルゴリズムを理解しようとしました。私はそれが何を言っているのか完全には理解していませんが、おそらく私の問題は、オブジェクトのプロパティが列挙可能でないことに関係しています(???)

簡単な回避策はありますか?


更新:W3Cは最終的に構造化クローン仕様についての考え方を変え、実装に合わせて仕様を変更することを決定しました。https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111を参照してください。したがって、この質問はもはや100%有効ではありませんが、答えはまだ興味深いかもしれません。


17
ところで、「構造化クローンアルゴリズム」の読み取りは正しいです。実装が終了した後、仕様が文字列のみの値からこれに変更されただけです。この問題を追跡するために、mozillaにバグbugzilla.mozilla.org/show_bug.cgi?id=538142を提出しました。
Nickolay、2010年

2
これはindexedDBの仕事のようです...
markasoftware 2013

1
オブジェクトの配列をlocalStorageに保存するのはどうですか?文字列に変換されるという同じ問題に直面しています。
Jayant Pareek 2017年

1
代わりに、配列をシリアル化できますか?JSON stringifyを使用してストアし、ロード時に再度解析するようなものですか?
Brandito 2018年

1
localDataStorageを使用して、JavaScriptデータ型(配列、ブール、日付、浮動小数点、整数、文字列、オブジェクト)を透過的に保存できます
Mac

回答:


3172

AppleMozilla、およびMozillaのドキュメントをもう一度見ると、機能は文字列のキーと値のペアのみを処理するように制限されているようです。

回避策は、オブジェクトを格納する前に文字列化し、後で取得するときに解析することです。

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));

160
メタデータが削除されることに注意してください。キーと値のペアを持つオブジェクトを取得するだけなので、動作のあるオブジェクトを再構築する必要があります。
オリゴフレン2013年

5
@CMSは、データが容量を超えている場合、setItemで例外をスローできますか?
アシッシュネギ2014年

3
...循環参照を持つオブジェクトにのみ適用さJSON.stringify()れ、文字列化するオブジェクト内の完全な「コンテンツ」(暗黙的に文字列化)に参照オブジェクトを展開します。参照:stackoverflow.com/a/12659424/2044940
CodeManX

3
この方法の問題は、大きな配列やオブジェクトを処理する必要がある場合のパフォーマンスの問題です。
マーク

3
@oligofrenはtrueですが、majaがeval()=>を正しく提案しているので、これはの良い使い方の1つです。関数コードを簡単に取得できます=>文字列として保存してから、eval()で戻すことができます:)
jave.web

621

バリアントのマイナーな改善:

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);
}

そのための短絡評価getObject()、すぐに戻るnull場合はkeyストレージではありません。またSyntaxErrorvalueis ""(空の文字列; JSON.parse()それを処理できない)の場合、例外はスローされません。


48
使用方法がすぐにはわからなかったので、すぐに使用法を追加したいだけです。 var userObject = { userId: 24, name: 'Jack Bauer' }; 設定 localStorage.setObject('user', userObject); してから、ストレージから取得しuserObject = localStorage.getObject('user'); ます。必要に応じて、オブジェクトの配列を保存 することもできます。
zuallauz 2011

8
単なるブール式です。2番目の部分は、左の部分がtrueの場合にのみ評価されます。その場合、式全体の結果は正しい部分になります。ブール式の評価方法に基づく人気の高いテクニックです。
グリア

4
ローカル変数とショートカット評価のポイントはここにはありません(マイナーなパフォーマンスの改善はさておき)。場合はkey、ローカルストレージではありませんwindow.localStorage.getItem(key)戻ってnull-それはないないと- 「不正アクセス」の例外をスローJSON.parse(null)リターンをnullそれはない-にもない、どちらもクロム21にもあたりのいずれかの例外をスローセクション15.12.2 ES 5.1、なぜならString(null) === "null"その缶JSONリテラルとして解釈されます
PointedEars 2012年

6
ローカルストレージの値は常にプリミティブな文字列値です。したがって、このショートカット評価が処理するのは、誰かが""(空の文字列)を以前に保存したときです。それはへのコンバートを入力しているためfalseJSON.parse("")投げることになる、SyntaxError例外を、呼び出されません。
PointedEars

2
これはIE8では機能しないため、サポートする必要がある場合は、確認済みの回答の関数を使用することをお勧めします。
2013年

220

次の便利なメソッドでStorageオブジェクトを拡張すると便利な場合があります。

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

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

これにより、APIの下では文字列しかサポートされていなくても、本当に必要な機能を利用できます。


13
CMSのアプローチを関数にラップするのは良い考えです。JSON.stringify、JSON.parse、そしてlocalStorageが実際にオブジェクトを設定および取得できるかどうかをテストする機能テストが必要です。ホストオブジェクトの変更はお勧めできません。私はこれを別の方法として見て、としてではなくむしろ見たいと思いlocalStorage.setObjectます。
Garrett

4
格納された値がの場合、これgetObject()を処理できないため、SyntaxError例外がスローされます。詳細については、Guriaの回答に対する私の編集を参照してください。""JSON.parse()
PointedEars 2012年

9
私の2セントだけですが、このようにベンダーから提供されたオブジェクトを拡張することはお勧めできません。
Sethen 14


73

Storageオブジェクトの拡張は素晴らしいソリューションです。私のAPIでは、localStorageのファサードを作成し、設定および取得中にそれがオブジェクトであるかどうかを確認しています。

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;
  }
}

1
これは私が必要としていたものとほぼ同じでした。if(value == null){return false}をコメントの前に追加する必要がありました。それ以外の場合は、localStorageのキーの存在を確認するときにエラーが発生しました。
Francesco Frapporti

2
これは実際にはかなりクールです。@FrancescoFrapportiに同意します。null値の場合、そこにある必要があります。'||も追加しました value [0] == "[" '配列がある場合のテスト。
rob_james 2012年

良い点、これを編集します。null部分は必要ありませんが、必要な場合は3つの===をお勧めします。JSHintまたはJSLintを使用する場合、==の使用に対して警告が表示されます。
Alex Grande

3
忍者以外(私のように)については、誰かがこの答えの使用例を教えていただけませんか?それdata.set('username': 'ifedi', 'fullname': { firstname: 'Ifedi', lastname: 'Okonkwo'});ですか?
Ifedi Okonkwo

はい、そうです!スプーンで食べたいという欲求を克服したとき、私はテストするためのコードを取り、それを手に入れました。この回答は素晴らしいと思います。1)受け入れられた回答とは異なり、文字列データに対して特定のチェックを行うには時間がかかります。2)次の回答とは異なり、ネイティブオブジェクトは拡張されません。
Ifedi Okonkwo

64

Stringifyはすべての問題を解決するわけではありません

ここでの答えはJavaScriptで可能なすべてのタイプを網羅しているわけではないようです。そのため、これらを正しく処理する方法についての短い例をいくつか示します。

//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"

eval()悪はセキュリティ、最適化、デバッグに関する問題を引き起こす可能性があるため、関数を保存することはお勧めません。一般に、eval()JavaScriptコードでは使用しないでください。

プライベートメンバー

JSON.stringify()オブジェクトの格納に使用する場合の問題は、この関数がプライベートメンバーをシリアル化できないことです。この問題は、.toString()メソッドを上書きすることで解決できます(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);

循環参照

stringify対処できないもう1つの問題は循環参照です。

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

この例でJSON.stringify()は、TypeError 「循環構造をJSONに変換」をスローします。循環参照の格納をサポートする必要がある場合は、2番目のパラメーターをJSON.stringify()使用できます。

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;
    }
});

ただし、循環参照を格納するための効率的なソリューションを見つけることは、解決する必要のあるタスクに大きく依存し、そのようなデータの復元も簡単ではありません。

この問題を処理するSOにはすでにいくつかの質問があります:循環参照を持つJavaScriptオブジェクトを文字列化(JSONに変換)します


2
したがって、言うまでもないことですが、ストレージへのデータの格納は、単純なデータのコピーの唯一の前提に基づいている必要があります。ライブオブジェクトではありません。
Roko C. Buljan

51

多くのソリューションをラップする素晴らしいライブラリーがあるので、jStorageと呼ばれる古いブラウザーもサポートします

オブジェクトを設定できます

$.jStorage.set(key, value)

そしてそれを簡単に取得

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

2
@SuperUberDuper jStorageには、Prototype、MooToolsまたはjQueryが必要
JProgrammer

28

理論的には、関数を含むオブジェクトを格納することが可能です。

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;
}

ただし、関数のシリアライゼーション/デシリアライゼーションは、実装に依存しているため信頼できませ


1
関数のシリアライゼーション/デシリアライゼーションは、実装に依存しているため信頼できませ。また、あなたが交換したいc.f[k] = escape(a[k]); のUnicodeセーフとc.f[k] = encodeURIComponent(a[k]);してeval('b.' + k + ' = ' + unescape(data.f[k]));b[k] = eval("(" + decodeURIComponent(data.f[k]) + ")");。関数が適切にシリアル化されている場合、匿名である可能性が高いため、括弧が必要です。これは、有効な/ Statement /ではないため(そうでない場合eval()SyntaxError例外をスローします)。
PointedEars 2012年

またtypeof演算子です。関数であるかのように記述しないでください。交換してくださいtypeof(a[k])typeof a[k]
PointedEars 2012年

私の提案を適用し、アプローチの信頼性を強調することに加えて、次のバグを修正しました。1.すべての変数が宣言されたわけではありません。2. for- in独自のプロパティについてフィルタリングされませんでした。3.参照を含むコードスタイルに一貫性がありませんでした。
PointedEars

@PointedEarsこれは実際にどのような違いがありますか?仕様によるthe use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent. と、機能的な違いは見られません。
Michael

@Michael引用した部分はで始まりますNote *in particular* that …。しかし、と戻り値の指定を開始するAn implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration.戻り値が可能function foo () {}-と仮定準拠した実装を。
PointedEars 2014年

22

これの複製として閉じられた別の投稿をヒットした後、「localstorageに配列を保存する方法」というタイトルのこの投稿に到達しました。どちらのスレッドもlocalStorageで配列を維持する方法に関して完全な答えを実際に提供しないことを除いて、これは問題ありませんが、両方のスレッドに含まれる情報に基づいてソリューションを作成できました。

したがって、他の誰かが配列内でアイテムをプッシュ/ポップ/シフトできるようにしたい場合、その配列をlocalStorageまたは実際にsessionStorageに格納したい場合は、次のようにします。

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);
}

使用例-localStorage配列に単純な文字列を格納します。

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

使用例-オブジェクトを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);

配列を操作する一般的な方法:

.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

これは、localStorageまたはsessionStorageに格納された配列を操作するための非常に便利な一連のメソッドであり、魅力的なものよりはるかに多くの価値があります。@Andy Lorenz共有してくれてありがとう!
Velojet 2017



6

localDataStorageを使用して、JavaScriptデータ型(配列、ブール、日付、浮動小数点、整数、文字列、オブジェクト)を透過的に格納できます。また、軽量のデータ難読化を提供し、文字列を自動的に圧縮し、キー(名前)によるクエリと(キー)値によるクエリを容易にし、キーにプレフィックスを付けることにより、同じドメイン内でセグメント化された共有ストレージを適用するのに役立ちます。

[免責事項]私はユーティリティの作成者です[/免責事項]

例:

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

ご覧のとおり、プリミティブ値が尊重されています。


1
これは素晴らしいリソースであり、私が必要としているものです。私はAngularJSでIonicアプリを実行していますが、特定のjavascriptオブジェクトをlocalStorageに保存する必要があります。これまで、JSON.parseとJSON.stringifyを実行してきましたが、これらは機能しますが、実行するのが少し面倒です。このようなユーティリティを使用するだけです。やってみます。
Nmuta

4

別のオプションは、既存のプラグインを使用することです。

たとえば、persistoはオープンソースプロジェクトであり、localStorage / sessionStorageへの簡単なインターフェースを提供し、フォームフィールド(入力、ラジオボタン、チェックボックス)の永続化を自動化します。

永続的な機能

(免責事項:私は著者です。)


まだreadmeに取り組んでいます、私のバージョンでは、persistoのようにjQuery は必要ありません、jQuery要素オブジェクトを処理するための代替手段を提供します。近い将来、さらに追加して、さまざまなjQueryオブジェクトをさらに処理し、永続データなどを維持できるようにする予定です。また、+ 1は、より簡単なソリューションを提供しようとするものです。また、従来の方法のすべてを使用しlocalStroageます。exp: var lsh = new localStorageHelper(); lsh.setItem('bob', 'bill');イベントも含まれます。
SpYk3HH

4

ejsonを使用してオブジェクトを文字列として保存できます。

EJSONは、より多くのタイプをサポートするためのJSONの拡張です。すべてのJSONセーフタイプに加えて、以下をサポートします。

  • 日付(JavaScript Date
  • Binary(JavaScript Uint8ArrayまたはEJSON.newBinaryの結果)
  • ユーザー定義タイプ(EJSON.addTypeを参照してください。たとえば、Mongo.ObjectIDはこの方法で実装されます)

すべてのEJSONシリアル化も有効なJSONです。たとえば、日付とバイナリバッファを持つオブジェクトは、EJSONで次のようにシリアル化されます。

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

これがejsonを使用した私のlocalStorageラッパーです

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

正規表現や関数など、いくつかのタイプをラッパーに追加しました


2

20行のコードで最小限のラッパーをもう1つ作成し、次のように使用できるようにしました。

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


2

Typescriptプロパティを設定して取得することをいとわないTypescriptユーザーの場合:

/**
 * 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");

2

https://github.com/adrianmay/rhabooは、次のようなものを記述できるlocalStorageシュガーレイヤーです。

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');

大きなオブジェクトではJSON.stringify / parseは不正確で遅いため、これは使用しません。代わりに、各端末値には独自のlocalStorageエントリがあります。

おそらく私はラブーと関係があるのではないかと推測できます。


1

@danottが投稿したコードの拡張バージョン

また、localstorageからの値の削除も実装し、代わりにGetterおよびSetterレイヤーを追加する方法を示します。

localstorage.setItem(preview, true)

あなたは書ける

config.preview = true

さて、ここに行きました:

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

ええと、エイリアスの部分をで取り除くことができます.bind(...)。しかし、これについて知っておくのは本当に良いので、私はそれを入れました。単純なものが機能get = localStorage.getItem;しない理由を見つけるのに何時間もかかった


1

私は既存のStorageオブジェクトを壊さないものを作りましたが、ラッパーを作成してあなたが望むことを行えるようにしました。結果は、通常のオブジェクトであり、メソッドはなく、他のオブジェクトと同じようにアクセスできます。

私が作ったもの。

1つのlocalStorageプロパティを魔法にしたい場合:

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

複数必要な場合:

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

あなたがするすべてprop、または内部 のオブジェクトstorageは自動的にに保存されlocalStorageます。あなたは常に実際のオブジェクトで遊んでいるので、次のようなことができます:

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

そして、追跡されたオブジェクト内のすべての新しいオブジェクトは自動的に追跡されます。

非常に大きな欠点:依存するObject.observe()ため、ブラウザーのサポートが非常に制限されます。また、FirefoxやEdgeにも近日中に登場するようには見えません。


1

文字列形式がないとキー値を保存できません。

LocalStorageは、キー/値の文字列形式のみをサポートします。

そのため、ArrayObjectを問わず、データを文字列に変換する必要があります。

データをlocalStorageに保存するには、まずJSON.stringify()メソッドを使用してデータを文字列化します

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

次に、データを取得する場合は、文字列をオブジェクトに再度解析する必要があります。

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

それが役に立てば幸い。


0

オブジェクトを格納するために、文字列からオブジェクトにオブジェクトを取得するために使用できる文字を作成できます(意味がない場合があります)。例えば

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"}

オブジェクトを分割するために使用した文字を使用すると、この手法はいくつかの不具合を引き起こします。また、これは非常に実験的なものです。


0

私はそれを循環参照を持つオブジェクトで動作させる方法を見つけました。

循環参照を持つオブジェクトを作ってみましょう。

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;

JSON.stringify循環参照のため、ここではできません。

円形おじさん

LOCALSTORAGE.CYCLICJSONは通常の.stringify.parse同じJSONですが、循環参照を持つオブジェクトで機能します。(「作品」はparse(stringify(obj))とobjが深く等しく、同一の「内部等式」のセットがあることを意味します)

ただし、ショートカットを使用するだけです。

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

次に、recovered次の意味でobjと「同じ」になります。

[
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
]

これはの実装です 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>


-2

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

次に、それをストアから取得して、もう一度オブジェクトに変換します。

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

ストアのすべてのエントリを削除する必要がある場合は、次のようにします。

localStorage.clear();


3
これは10年前の質問です。あなたの答えは、他の答えでまだカバーされていない何かを追加すると思いますか?
クリストファージョンソン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.