Хранение объектов в HTML5 localStorage - PullRequest
2303 голосов
/ 06 января 2010

Я хотел бы сохранить объект 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 * Web5 Storage , а не ошибка браузера или ограничение.

Я пытался разобраться в алгоритме структурированного клона , описанном в http://www.w3.org/TR/html5/infrastructure.html. Я не до конца понимаю, что он говорит, но, возможно, моя проблема связана со свойствами моего объекта не перечисляемый (???)

Есть ли простой обходной путь?


Обновление: W3C в конечном итоге изменил свое мнение о спецификации структурированных клонов и решил изменить спецификацию в соответствии с реализациями. См. https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111. Так что этот вопрос более не является действительным на 100%, но ответы все еще могут представлять интерес.

Ответы [ 27 ]

1 голос
/ 28 ноября 2015

Я сделал вещь, которая не ломает существующие объекты 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 голос
/ 21 мая 2016

Чтобы сохранить объект, вы можете сделать буквы, которые вы можете использовать, чтобы получить объект из строки в объект (может не иметь смысла). Например

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

Эта техника вызовет некоторые сбои, если вы используете букву, которую вы использовали для разделения объекта, и она также очень экспериментальна.

1 голос
/ 04 декабря 2015

Смотрите это

Допустим, у вас есть следующий массив под названием movies:

var movies = ["Reservoir Dogs", "Pulp Fiction", "Jackie Brown", 
              "Kill Bill", "Death Proof", "Inglourious Basterds"];

Используя функцию stringify, ваш массив фильмов можно преобразовать в строку, используя следующий синтаксис:

localStorage.setItem("quentinTarantino", JSON.stringify(movies));

Обратите внимание, что мои данные хранятся под ключом quentinTarantino.

Получение ваших данных

var retrievedData = localStorage.getItem("quentinTarantino");

Чтобы преобразовать строку обратно в объект, используйте функцию анализа JSON:

var movies2 = JSON.parse(retrievedData);

Вы можете вызывать все методы массива в своих фильмах2

1 голос
/ 05 июня 2014

Небольшой пример библиотеки, которая использует localStorage для отслеживания полученных сообщений от контактов:

// This class is supposed to be used to keep a track of received message per contacts.
// You have only four methods:

// 1 - Tells you if you can use this library or not...
function isLocalStorageSupported(){
    if(typeof(Storage) !== "undefined" && window['localStorage'] != null ) {
         return true;
     } else {
         return false;
     }
 }

// 2 - Give the list of contacts, a contact is created when you store the first message
 function getContacts(){
    var result = new Array();
    for ( var i = 0, len = localStorage.length; i < len; ++i ) {
        result.push(localStorage.key(i));
    }
    return result;
 }

 // 3 - store a message for a contact
 function storeMessage(contact, message){
    var allMessages;
    var currentMessages = localStorage.getItem(contact);
    if(currentMessages == null){
        var newList = new Array();
        newList.push(message);
        currentMessages = JSON.stringify(newList);
    }
    else
    {
        var currentList =JSON.parse(currentMessages);
        currentList.push(message);
        currentMessages = JSON.stringify(currentList);
    }
    localStorage.setItem(contact, currentMessages);
 }

 // 4 - read the messages of a contact
 function readMessages(contact){

    var result = new Array();
    var currentMessages = localStorage.getItem(contact);

    if(currentMessages != null){
        result =JSON.parse(currentMessages);
    }
    return result;
 }
1 голос
/ 10 февраля 2015

Вот некоторая расширенная версия кода, размещенная @ danott

Также будет реализовано удаление значения из localalstorage и показывает, как добавить слой 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; не работает

0 голосов
/ 27 июня 2019

Localstorage может хранить только пары ключ-значение, где оба ключа и значения должны быть строками . Однако вы можете сохранить объект, сериализовав их в строки JSON, а затем десериализовать их в объекты JS при извлечении их.

Например:

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

// JSON.stringify turns a JS object into a JSON string, thus we can store it
localStorage.setItem('testObject', JSON.stringify(testObject));

// After we recieve a JSON string we can parse it into a JS object using JSON.parse
var jsObject = JSON.parse(localStorage.getItem('testObject')); 

Имейте в виду, что это удалит установленную цепочку прототипов. Лучше всего это показать на примере:

function testObject () {
  this.one = 1;
  this.two = 2;
  this.three = 3;
}

testObject.prototype.hi = 'hi';

var testObject1 = new testObject();

// logs the string hi, derived from prototype
console.log(testObject1.hi);

// the prototype of testObject1 is testObject.prototype
console.log(Object.getPrototypeOf(testObject1));

// stringify and parse the js object, will result in a normal JS object
var parsedObject = JSON.parse(JSON.stringify(testObject1));

// the newly created object now has Object.prototype as its prototype 
console.log(Object.getPrototypeOf(parsedObject) === Object.prototype);
// no longer is testObject the prototype
console.log(Object.getPrototypeOf(parsedObject) === testObject.prototype);

// thus we cannot longer access the hi property since this was on the prototype
console.log(parsedObject.hi); // undefined
0 голосов
/ 02 июня 2016

Loop через локальное хранилище

var retrievedData = localStorage.getItem("MyCart");                 

retrievedData.forEach(function (item) {
   console.log(item.itemid);
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...