javascript - تخزين الكائنات في HTML5 التخزين المحلي




local-storage (18)

Stringify لا يحل جميع المشاكل

يبدو أن الإجابات هنا لا تغطي جميع الأنواع الممكنة في جافا سكريبت ، لذا إليك بعض الأمثلة القصيرة حول كيفية التعامل معها بشكل صحيح:

//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() طريقة (التي تسمى بشكل ضمني عند تخزين البيانات في تخزين الويب):

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

المراجع الدائرية

مشكلة أخرى لا يمكن التعامل معها هي مراجع دائرية:

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

في هذا المثال ، JSON.stringify() برمي TypeError "تحويل بنية دائرية إلى JSON" . إذا كان يجب دعم المراجع الدائرية ، فيمكن استخدام المعلمة الثانية من 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 تتعامل مع هذه المشكلة: Stringify (convert to JSON) a JavaScript object with reference reference

أود تخزين كائن جافا سكريبت في localStorage ، ولكن يبدو أن الكائن يتم تحويله إلى سلسلة.

يمكنني تخزين واسترداد أنواع ومجموعات جافا سكريبت البدائية باستخدام 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 ٪ ، ولكن الأجوبة ما زالت تثير الاهتمام.


استخدام كائنات JSON للتخزين المحلي:

//جلس

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

//احصل على

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

// تكرار جميع مفاتيح وقيم التخزين المحلية

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

// حذف

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

تحسين طفيف على variant :

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

وبسبب تقييم short-circuit ، getObject() null الفور إذا لم يكن key في التخزين. فإنه أيضاً لن يتم SyntaxError استثناء SyntaxError إذا كانت value "" (السلسلة الفارغة ؛ لا يمكن معالجة JSON.parse() ذلك).


تحسين على إجابةGuria:

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


Storage.prototype.getObject = function (key) {
    var value = this.getItem(key);
    try {
        return JSON.parse(value);
    }
    catch(err) {
        console.log("JSON parse failed for lookup of ", key, "\n error was: ", err);
        return null;
    }
};

توسيع كائن التخزين هو حل رائع. بالنسبة إلى واجهة برمجة التطبيقات الخاصة بي ، قمت بإنشاء واجهة لـ StorStage المحلي ثم تحقق مما إذا كان كائنًا أم لا أثناء الإعداد والتشغيل.

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

خيار آخر هو استخدام البرنامج المساعد الحالي.

على سبيل المثال ، persisto هو مشروع مفتوح المصدر يوفر واجهة سهلة إلى persisto ، وأتمتة المثابرة لحقول النموذج (المدخلات ، أزرار الاختيار ، ومربعات الاختيار).

(إخلاء المسؤولية: أنا مؤلف.)


لقد صنعت شيئًا لا يكسر كائنات التخزين الحالية ، ولكنه ينشئ غلافًا حتى يمكنك فعل ما تريد. والنتيجة هي كائن عادي ، لا توجد طرق ، مع الوصول مثل أي كائن.

الشيء الذي صنعته

إذا كنت تريد أن تكون خاصية localStorage واحدة سحرية:

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

إذا كنت بحاجة إلى عدة:

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

سيتم حفظ كل ما تفعله prop ، أو الكائنات الموجودة داخل storage تلقائيًا في storage localStorage . أنت دائمًا تلعب مع كائن حقيقي ، حتى تتمكن من القيام بأشياء مثل هذه:

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

وسيتم تعقب كل كائن جديد داخل كائن متتبع تلقائيا.

الجانب السلبي الكبير للغاية: يعتمد ذلك على Object.observe() بحيث يكون لديه دعم متصفح محدود للغاية. ولا يبدو أنها ستأتي لـ Firefox أو Edge في أي وقت قريب.


لقد صنعت غلافًا آخر في أضيق الحدود مع 20 سطرًا فقط من الشفرة للسماح باستخدامه كما ينبغي:

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


من الأفضل أن تقوم بوظائف كمؤشر ورابح إلى التخزين المحلي ، وبهذه الطريقة سيكون لديك تحكم أفضل ولن تضطر إلى تكرار تحليل JSON وكل شيء. سيتعامل مع حالة مفتاح / بيانات السلسلة الفارغة ("") بسلاسة.

function setItemInStorage(dataKey, data){
    localStorage.setItem(dataKey, JSON.stringify(data));
}

function getItemFromStorage(dataKey){
    var data = localStorage.getItem(dataKey);
    return data? JSON.parse(data): null ;
}

setItemInStorage('user', { name:'tony stark' });
getItemFromStorage('user'); /* return {name:'tony stark'} */

نظريًا ، من الممكن تخزين الكائنات بوظائف:

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

ومع ذلك ، فإن عملية التسلسل / إلغاء التسلسل الوظيفي تكون غير موثوقة لأنها تعتمد على التنفيذ .


هنا بعض نسخة حد من رمز نشرهاdotott

كما سيقوم أيضًا بتطبيق حذف القيمة من 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; لا تعمل


وبالنظر إلى مستندات Apple و Mozilla و Microsoft ، يبدو أن الوظيفة محدودة في التعامل مع أزواج المفاتيح / القيم في السلسلة فقط.

يمكن أن يكون الحل البديل stringify الكائن الخاص بك قبل تخزينه ، وبعد ذلك تحليله عند استعادته:

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

يمكنك أيضًا تجاوز setItem(key,value) الافتراضي للتخزين setItem(key,value) وطرق getItem(key) للتعامل مع الكائنات / الصفائف مثل أي نوع بيانات آخر. بهذه الطريقة ، يمكنك ببساطة استدعاء localStorage.setItem(key,value) و localStorage.getItem(key) كما تفعل عادةً.

لم أختبر هذا على نطاق واسع ، ولكن يبدو أنه يعمل دون مشاكل لمشروع صغير كنت أتلاعب به.

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

يمكنك استخدام ejson لتخزين الكائنات ejson .

EJSON هو امتداد لـ JSON لدعم المزيد من الأنواع. يدعم جميع أنواع JSON الآمنة ، بالإضافة إلى:

  • التاريخ (تاريخ جافا سكريبت)
  • ثنائي (JavaScript Uint8Array أو نتيجة EJSON.newBinary )
  • أنواع المعرفة من قبل المستخدم (انظر EJSON.addType . على سبيل المثال ، يتم تنفيذ Mongo.ObjectID بهذه الطريقة.)

جميع عمليات التسلسل EJSON صالحة أيضًا لـ JSON. على سبيل المثال ، يمكن إجراء تسلسل كائن له تاريخ ومخزن مؤقت ثنائي في EJSON على النحو التالي:

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

هنا هو بلدي مجمعات التخزين المحلية باستخدام ejson

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

أضفت بعض الأنواع إلى المجمع الخاص بي بما في ذلك التعبيرات والوظائف العادية


http://rhaboo.org هي طبقة سكر محلية تسمح لك بكتابة أشياء مثل:

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 الخاص بها.

ربما يمكنك تخمين أنني قد يكون لها علاقة مع rhaboo ؛-)

أدريان.


انظروا الى هذا

لنفترض أن لديك الصفيف التالي المسمى الأفلام:

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 parse:

var movies2 = JSON.parse(retrievedData);

يمكنك الاتصال بكافة طرق الصفيف على أفلامك 2


حلقة عبر localstorage

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

retrievedData.forEach(function (item) {
   console.log(item.itemid);
});

مثال صغير على مكتبة تستخدم 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;
 }




local-storage