Lưu trữ các đối tượng trong HTML5 localStorage


2511

Tôi muốn lưu trữ một đối tượng JavaScript trong HTML5 localStorage, nhưng đối tượng của tôi rõ ràng đang được chuyển đổi thành một chuỗi.

Tôi có thể lưu trữ và truy xuất các loại và mảng JavaScript nguyên thủy bằng cách sử dụng localStorage, nhưng các đối tượng dường như không hoạt động. Họ nên?

Đây là mã của tôi:

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

Đầu ra giao diện điều khiển là

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

Có vẻ như setItemphương thức này đang chuyển đổi đầu vào thành một chuỗi trước khi lưu trữ nó.

Tôi thấy hành vi này trong Safari, Chrome và Firefox, vì vậy tôi cho rằng đó là sự hiểu lầm của tôi về thông số lưu trữ web HTML5 , không phải là lỗi hoặc giới hạn dành riêng cho trình duyệt.

Tôi đã cố gắng hiểu ý nghĩa của thuật toán nhân bản có cấu trúc được mô tả trong http://www.w3.org/TR/html5/infr kia.html . Tôi không hoàn toàn hiểu những gì nó nói, nhưng có lẽ vấn đề của tôi liên quan đến các thuộc tính của đối tượng của tôi không được liệt kê (???)

Có một cách giải quyết dễ dàng?


Cập nhật: W3C cuối cùng đã thay đổi suy nghĩ của họ về đặc tả bản sao có cấu trúc và quyết định thay đổi thông số kỹ thuật để phù hợp với việc triển khai. Xem https://www.w3.org/Bugs/Public/show_orms.cgi?id=12111 . Vì vậy, câu hỏi này không còn hợp lệ 100%, nhưng câu trả lời vẫn có thể được quan tâm.


17
BTW, việc bạn đọc "thuật toán nhân bản có cấu trúc" là chính xác, chỉ là thông số kỹ thuật đã được thay đổi từ các giá trị chỉ chuỗi thành giá trị này sau khi triển khai xong. Tôi đã gửi bug bugzilla.mozilla.org/show_orms.cgi?id=538142 với mozilla để theo dõi vấn đề này.
Nickolay

2
Đây có vẻ như là một công việc cho indexedDB ...
markasoftware

1
Làm thế nào về việc lưu trữ một mảng các Đối tượng trong localStorage? Tôi đang đối mặt với cùng một vấn đề rằng nó đang được chuyển đổi thành chuỗi.
Jayant Pareek

1
thay vào đó bạn có thể tuần tự hóa mảng? như lưu trữ với JSON stringify sau đó phân tích lại khi tải?
Brandito

1
Bạn có thể sử dụng localDataStorage để lưu trữ trong suốt các loại dữ liệu javascript (Array, Boolean, Date, Float, Integer, String và Object)
Mac

Câu trả lời:


3172

Nhìn vào Apple , MozillaMozilla một lần nữa tài liệu , chức năng dường như bị giới hạn chỉ xử lý các cặp khóa / giá trị chuỗi.

Một cách giải quyết có thể là xâu chuỗi đối tượng của bạn trước khi lưu trữ nó và sau đó phân tích cú pháp khi bạn truy xuất nó:

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
quan sát rằng bất kỳ siêu dữ liệu sẽ được loại bỏ. bạn chỉ cần lấy một đối tượng với các cặp khóa-giá trị, vì vậy bất kỳ đối tượng nào có hành vi cần phải được xây dựng lại.
oligofren

5
@CMS có thể setItem ném một số ngoại lệ nếu dữ liệu vượt quá dung lượng không?
Ashish Negi

3
... chỉ áp dụng cho các đối tượng chỉ có tham chiếu vòng tròn, JSON.stringify()mở rộng đối tượng được tham chiếu thành "nội dung" đầy đủ của nó (được xâu chuỗi ngầm) trong đối tượng chúng tôi xâu chuỗi. Xem: stackoverflow.com/a/12659424/2044940
CodeManX

3
Vấn đề với phương pháp này là vấn đề hiệu năng, nếu bạn phải xử lý các mảng hoặc đối tượng lớn.
Đánh dấu

3
@oligofren đúng, nhưng như maja đã đề xuất chính xác eval () =>, đây là một trong những cách sử dụng tốt, bạn có thể dễ dàng truy xuất mã chức năng => lưu trữ dưới dạng chuỗi và sau đó eval () gửi lại :)
jave.web

621

Một cải tiến nhỏ trên một biến thể :

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

Do đánh giá ngắn mạch , getObject()sẽ ngay lập tức quay lại nullnếu keykhông có trong Bộ lưu trữ. Nó cũng sẽ không ném SyntaxErrorngoại lệ nếu value""(chuỗi rỗng; JSON.parse()không thể xử lý điều đó).


48
Tôi chỉ muốn nhanh chóng thêm cách sử dụng vì nó không rõ ràng ngay lập tức đối với tôi: var userObject = { userId: 24, name: 'Jack Bauer' }; Và để thiết lập nó localStorage.setObject('user', userObject); Sau đó lấy lại từ bộ lưu trữ userObject = localStorage.getObject('user'); Bạn thậm chí có thể lưu trữ một mảng các đối tượng nếu bạn muốn.
zuallauz

8
Nó chỉ là biểu thức boolean. Phần thứ hai chỉ được đánh giá nếu còn lại một là đúng. Trong trường hợp đó, kết quả của toàn bộ biểu thức sẽ từ phần bên phải. Đây là kỹ thuật phổ biến dựa trên cách đánh giá các biểu thức boolean.
Guria

4
Tôi không thấy điểm của biến cục bộ và đánh giá phím tắt ở đây (cải thiện hiệu suất nhỏ sang một bên). Nếu keykhông có trong Bộ nhớ cục bộ, window.localStorage.getItem(key)trả về null- nó sẽ không ném ngoại lệ "Truy cập bất hợp pháp" - và cũng JSON.parse(null)trả về null- nó cũng không ném ngoại lệ, trong Chromium 21 cũng không theo ES 5.1, phần 15.12.2 , bởi vì String(null) === "null"có thể được hiểu là một chữ JSON .
PointedEars

6
Các giá trị trong Local Storage luôn là các giá trị chuỗi nguyên thủy. Vì vậy, những gì đánh giá lối tắt này xử lý là khi ai đó được lưu trữ ""(chuỗi trống) trước đó. Bởi vì nó chuyển đổi thành falseJSON.parse(""), sẽ ném SyntaxErrorngoại lệ, không được gọi.
PointedEars

2
Điều này sẽ không hoạt động trong IE8, vì vậy bạn nên sử dụng các chức năng trong câu trả lời được xác nhận nếu bạn cần hỗ trợ nó.
Ezeke

220

Bạn có thể thấy hữu ích khi mở rộng đối tượng Storage bằng các phương thức tiện dụng sau:

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

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

Bằng cách này, bạn có được chức năng mà bạn thực sự muốn mặc dù bên dưới API chỉ hỗ trợ các chuỗi.


13
Kết hợp cách tiếp cận của CMS vào một chức năng là một ý tưởng hay, nó chỉ cần một bài kiểm tra tính năng: Một cho JSON.opesify, một cho JSON.parse và một để kiểm tra xem trên thực tế localStorage có thể thiết lập và truy xuất một đối tượng hay không. Sửa đổi các đối tượng máy chủ không phải là một ý tưởng tốt; Tôi thà xem đây là một phương pháp riêng biệt chứ không phải là localStorage.setObject.
Garrett

4
Điều này getObject()sẽ đưa ra một SyntaxErrorngoại lệ nếu giá trị được lưu trữ "", bởi vì JSON.parse()không thể xử lý điều đó. Xem chỉnh sửa của tôi để trả lời của Guria để biết chi tiết.
PointedEars

9
Chỉ hai xu của tôi, nhưng tôi khá chắc chắn rằng không nên mở rộng các đối tượng được cung cấp bởi nhà cung cấp như thế này.
Sethen


73

Mở rộng đối tượng Storage là một giải pháp tuyệt vời. Đối với API của tôi, tôi đã tạo một mặt tiền cho localStorage và sau đó kiểm tra xem nó có phải là một đối tượng hay không trong khi cài đặt và nhận.

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
Đây gần như chính xác là những gì tôi cần. Chỉ cần thêm if (value == null) {return false} trước khi nhận xét, nếu không, nó sẽ dẫn đến lỗi khi kiểm tra sự tồn tại của khóa trên localStorage.
Francesco Frapporti

2
Điều này là khá mát mẻ thực sự. Đồng ý với @FrancescoFrapporti bạn cần một giá trị null. Tôi cũng đã thêm một '|| giá trị [0] == "[" 'kiểm tra trong trường hợp có một mảng trong đó.
rob_james

Điểm tốt, tôi sẽ chỉnh sửa này. Mặc dù bạn không cần phần null, nhưng nếu bạn làm tôi khuyên bạn nên ba ===. Nếu bạn sử dụng JSHint hoặc JSLint, bạn sẽ được cảnh báo không sử dụng ==.
Alex Grande

3
Và đối với những người không phải ninja (như tôi), ai đó có thể vui lòng cung cấp một ví dụ sử dụng cho câu trả lời này không? Có phải nó data.set('username': 'ifedi', 'fullname': { firstname: 'Ifedi', lastname: 'Okonkwo'});không?
Ifedi Okonkwo

Vâng thực sự! Khi tôi vượt qua mong muốn được cho ăn bằng thìa, tôi lấy mã để kiểm tra và lấy nó. Tôi nghĩ rằng câu trả lời này rất hay vì 1) Không giống như câu trả lời được chấp nhận, cần có thời gian để thực hiện một số kiểm tra nhất định đối với dữ liệu chuỗi và 2) Không giống như câu tiếp theo, nó không mở rộng đối tượng gốc.
Ifedi Okonkwo

64

Stringify không giải quyết tất cả các vấn đề

Dường như các câu trả lời ở đây không bao gồm tất cả các loại có thể có trong JavaScript, vì vậy đây là một số ví dụ ngắn về cách xử lý chúng một cách chính xác:

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

Tôi không khuyên bạn nên lưu trữ các chức năng vì eval()điều ác có thể dẫn đến các vấn đề liên quan đến bảo mật, tối ưu hóa và gỡ lỗi. Nói chung,eval() không bao giờ nên được sử dụng trong mã JavaScript.

Thành viên tư nhân

Vấn đề với việc sử dụng JSON.stringify()để lưu trữ các đối tượng là, chức năng này không thể tuần tự hóa các thành viên riêng. Vấn đề này có thể được giải quyết bằng cách ghi đè .toString()phương thức (được gọi là ngầm khi lưu trữ dữ liệu trong bộ lưu trữ 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);

Tài liệu tham khảo thông tư

Một vấn đề khác stringify không thể giải quyết là các tài liệu tham khảo vòng tròn:

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

Trong ví dụ này, JSON.stringify()sẽ đưa ra TypeError "Chuyển đổi cấu trúc vòng tròn thành JSON" . Nếu lưu trữ tham chiếu vòng tròn nên được hỗ trợ, tham số thứ hai JSON.stringify()có thể được sử dụng:

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

Tuy nhiên, việc tìm một giải pháp hiệu quả để lưu trữ các tham chiếu vòng tròn phụ thuộc rất nhiều vào các nhiệm vụ cần giải quyết và việc khôi phục dữ liệu đó cũng không phải là chuyện nhỏ.

Đã có một số câu hỏi về SO xử lý vấn đề này: Stringify (chuyển đổi thành JSON) một đối tượng JavaScript có tham chiếu vòng tròn


2
Do đó, và không cần phải nói - lưu trữ dữ liệu vào Storage nên dựa trên tiền đề duy nhất là các bản sao của dữ liệu đơn giản. Không phải đối tượng sống.
Roko C. Buljan

51

Có một thư viện tuyệt vời bao bọc nhiều giải pháp để nó thậm chí còn hỗ trợ các trình duyệt cũ hơn được gọi là jStorage

Bạn có thể thiết lập một đối tượng

$.jStorage.set(key, value)

Và lấy nó dễ dàng

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

2
@SuperUberDuper jStorage yêu cầu Prototype, MooTools hoặc jQuery
JProgrammer

28

Về lý thuyết, có thể lưu trữ các đối tượng có chức năng:

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

Tuy nhiên, tuần tự hóa / giải tuần tự hóa chức năng là không đáng tin cậy vì nó phụ thuộc vào việc thực hiện .


1
Chức năng tuần tự hóa / giải tuần tự hóa là không đáng tin cậy vì nó phụ thuộc vào việc thực hiện . Ngoài ra, bạn muốn thay thế c.f[k] = escape(a[k]); bằng Unicode an toàn c.f[k] = encodeURIComponent(a[k]);eval('b.' + k + ' = ' + unescape(data.f[k]));bằng b[k] = eval("(" + decodeURIComponent(data.f[k]) + ")");. Các dấu ngoặc đơn là bắt buộc vì hàm của bạn, nếu được xê-ri hóa đúng cách, có khả năng là ẩn danh, không phải là hợp lệ / Tuyên bố / (vì vậy eval()) sẽ ném SyntaxErrorngoại lệ theo cách khác).
PointedEars

typeoflà một toán tử , đừng viết nó như thể nó là một hàm. Thay thế typeof(a[k])bằng typeof a[k].
PointedEars

Ngoài việc áp dụng các đề xuất của tôi và nhấn mạnh sự không đáng tin cậy của phương pháp này, tôi đã sửa các lỗi sau: 1. Không phải tất cả các biến đều được khai báo. 2. for- inkhông được lọc cho các thuộc tính riêng. 3. Kiểu mã, bao gồm cả tham chiếu, không nhất quán.
PointedEars

@PointedEars điều này thực sự khác biệt gì? Thông số kỹ thuật nói rằng the use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent. tôi không thấy bất kỳ sự khác biệt về chức năng.
Michael

@Michael Phần mà bạn trích dẫn bắt đầu bằng Note *in particular* that …. Nhưng đặc tả giá trị trả về bắt đầu bằng An implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration.Giá trị trả về có thể function foo () {}- giả sử thực hiện tuân thủ .
PointedEars

22

Tôi đã đến bài đăng này sau khi nhấn vào một bài đăng khác đã bị đóng như là một bản sao của bài viết này - có tiêu đề 'làm thế nào để lưu trữ một mảng trong lưu trữ cục bộ?'. Sẽ tốt thôi, ngoại trừ chủ đề không thực sự cung cấp câu trả lời đầy đủ về cách bạn có thể duy trì một mảng trong localStorage - tuy nhiên tôi đã quản lý để tạo ra một giải pháp dựa trên thông tin có trong cả hai luồng.

Vì vậy, nếu bất cứ ai khác muốn có thể đẩy / pop / shift các mục trong một mảng và họ muốn mảng đó được lưu trữ trong localStorage hoặc thực sự là sessionStorage, thì bạn hãy vào đây:

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

sử dụng ví dụ - lưu trữ các chuỗi đơn giản trong mảng localStorage:

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

sử dụng ví dụ - lưu trữ các đối tượng trong mảng 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);

Các phương pháp phổ biến để thao tác mảng:

.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

Đây là một tập hợp các phương thức rất tiện dụng để thao tác các mảng được lưu trữ trong localStorage hoặc sessionStorage và xứng đáng nhận được nhiều tín dụng hơn mức thu hút. @Andy Lorenz Cảm ơn bạn đã dành thời gian chia sẻ!
Velojet



6

Bạn có thể sử dụng localDataStorage để lưu trữ trong suốt các kiểu dữ liệu javascript (Array, Boolean, Date, Float, Integer, String và Object). Nó cũng cung cấp mã hóa dữ liệu nhẹ, tự động nén chuỗi, tạo điều kiện truy vấn theo khóa (tên) cũng như truy vấn theo giá trị (khóa) và giúp thực thi lưu trữ được chia sẻ phân đoạn trong cùng một miền bằng các khóa tiền tố.

[TUYÊN BỐ TỪ CHỐI] Tôi là tác giả của tiện ích [/ DISCLAIMER]

Ví dụ:

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

Như bạn có thể thấy, các giá trị nguyên thủy được tôn trọng.


1
Đây là một nguồn tài nguyên tuyệt vời và chỉ là những gì tôi cần. Tôi đang làm các ứng dụng Ionic với AngularJS, nơi tôi cần lưu một số đối tượng javascript nhất định trong localStorage và cho đến thời điểm này tôi mới làm JSON.parse và JSON.opesify, và chúng hoạt động, nhưng nó hơi cồng kềnh hơn khả năng chỉ sử dụng một tiện ích như thế này. Tôi sẽ thử nó.
Nmuta

4

Một lựa chọn khác là sử dụng một plugin hiện có.

Ví dụ, Perso là một dự án nguồn mở cung cấp giao diện dễ dàng cho localStorage / sessionStorage và tự động hóa tính bền vững cho các trường biểu mẫu (đầu vào, nút radio và hộp kiểm).

tính năng kiên trì

(Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả.)


Vẫn hoạt động trên readme của tôi, nhưng phiên bản của tôi không yêu cầu jQuery, vì nó xuất hiện liên tục, nhưng nó cung cấp một giải pháp thay thế để xử lý các Đối tượng phần tử jQuery. Tôi sẽ bổ sung thêm trong tương lai gần, khi tôi làm việc với nó nhiều hơn, để giúp nó xử lý hơn nữa các Đối tượng jQuery khác nhau và duy trì những thứ như dữ liệu liên tục. Ngoài ra, +1 để cố gắng cung cấp một giải pháp đơn giản hơn! Ngoài ra, nó sử dụng tất cả các phương pháp truyền thống localStroage; exp: var lsh = new localStorageHelper(); lsh.setItem('bob', 'bill'); Cũng bao gồm các sự kiện.
SpYk3HH

4

Bạn có thể sử dụng ejson để lưu trữ các đối tượng dưới dạng chuỗi.

EJSON là một phần mở rộng của JSON để hỗ trợ nhiều loại hơn. Nó hỗ trợ tất cả các loại an toàn JSON, cũng như:

  • Ngày (JavaScript Date)
  • Nhị phân (JavaScript Uint8Arrayhoặc kết quả của EJSON.newBinary )
  • Các loại do người dùng xác định (xem EJSON.addType . Ví dụ: Mongo.ObjectID được triển khai theo cách này.)

Tất cả các tuần tự hóa EJSON cũng là JSON hợp lệ. Ví dụ: một đối tượng có ngày và bộ đệm nhị phân sẽ được tuần tự hóa trong EJSON như:

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

Đây là trình bao bọc localStorage của tôi bằng ejson

https://github.com/UziTech/st Storage.js

Tôi đã thêm một số loại vào trình bao bọc của mình, bao gồm các biểu thức và hàm thông thường


2

Tôi đã tạo một trình bao bọc tối giản khác chỉ với 20 dòng mã để cho phép sử dụng nó như nó nên:

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/simpleWebst Storage


2

Đối với người dùng Bản mô tả sẵn sàng đặt và nhận các thuộc tính được nhập:

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

Ví dụ sử dụng :

// 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 là một lớp đường LocalStorage cho phép bạn viết những thứ như thế này:

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

Nó không sử dụng JSON.opesify / parse vì điều đó sẽ không chính xác và chậm trên các đối tượng lớn. Thay vào đó, mỗi giá trị đầu cuối có mục nhập LocalStorage riêng.

Bạn có thể đoán rằng tôi có thể có một cái gì đó để làm với rhaboo.


1

Dưới đây là một số phiên bản mở rộng của mã được đăng bởi @danott

Nó cũng sẽ triển khai giá trị xóa khỏi bộ lưu trữ cục bộ và chỉ ra cách thêm lớp Getter và Setter thay vì

localstorage.setItem(preview, true)

bạn có thể viết

config.preview = true

Được rồi ở đây đã đi:

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

Vâng, bạn có thể tước phần bí danh với .bind(...). Tuy nhiên tôi chỉ cần đặt nó vào vì nó thực sự tốt để biết về điều này. Tôi đã mất hàng giờ để tìm hiểu lý do tại sao một get = localStorage.getItem;công việc đơn giản không hoạt động


1

Tôi đã tạo một thứ không phá vỡ các đối tượng Storage hiện có, nhưng tạo một trình bao bọc để bạn có thể làm những gì bạn muốn. Kết quả là một đối tượng bình thường, không có phương thức, với quyền truy cập như bất kỳ đối tượng nào.

Những điều tôi đã làm.

Nếu bạn muốn 1 localStoragetài sản là ma thuật:

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

Nếu bạn cần một số:

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

Mọi thứ bạn làm prophoặc các đối tượng bên trong storage sẽ được lưu tự động vào localStorage. Bạn luôn chơi với một vật thật, vì vậy bạn có thể làm những thứ như thế này:

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

Và mọi đối tượng mới bên trong một đối tượng được theo dõi sẽ được tự động theo dõi.

Nhược điểm rất lớn: nó phụ thuộc vào Object.observe()vì vậy nó có hỗ trợ trình duyệt rất hạn chế. Và có vẻ như nó sẽ không xuất hiện trên Firefox hay Edge bất cứ lúc nào.


1

Bạn không thể lưu trữ giá trị khóa mà không có Định dạng chuỗi .

LocalStorage chỉ hỗ trợ định dạng Chuỗi cho khóa / giá trị.

Đó là lý do tại sao bạn nên chuyển đổi dữ liệu của mình thành chuỗi bất kể đó là Array hay Object .

Để lưu trữ dữ liệu trong localStorage trước hết, hãy xâu chuỗi nó bằng phương thức JSON.opesify () .

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

Sau đó, khi bạn muốn lấy dữ liệu, bạn cần phân tích lại Chuỗi thành Đối tượng.

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

Hy vọng nó giúp.


0

Để lưu trữ một đối tượng, bạn có thể tạo một chữ cái mà bạn có thể sử dụng để đưa một đối tượng từ một chuỗi sang một đối tượng (có thể không có ý nghĩa). Ví dụ

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

Kỹ thuật này sẽ gây ra một số trục trặc nếu bạn sử dụng chữ cái mà bạn đã sử dụng để phân tách đối tượng và nó cũng rất thử nghiệm.


0

Tôi tìm thấy một cách để làm cho nó hoạt động với các đối tượng có tham chiếu theo chu kỳ.

Hãy tạo một đối tượng với các tham chiếu theo chu kỳ.

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;

Chúng tôi không thể làm JSON.stringifyở đây, vì các tài liệu tham khảo thông tư.

thông tư

LOCALSTORAGE.CYCLICJSON.stringify.parsegiống như bình thường JSON, nhưng hoạt động với các đối tượng có tham chiếu tròn. ("Tác phẩm" có nghĩa là phân tích cú pháp (Stringify (obj)) và obj là bằng nhau sâu sắc và có các bộ 'đẳng thức bên trong' giống hệt nhau)

Nhưng chúng ta chỉ có thể sử dụng các phím tắt:

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

Sau đó, recoveredsẽ là "giống nhau" với obj, theo nghĩa sau:

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

Đây là việc thực hiện 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 ('người dùng', JSON.opesify (người dùng));

Sau đó, để lấy nó từ cửa hàng và chuyển đổi thành một đối tượng một lần nữa:

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

Nếu chúng ta cần xóa tất cả các mục của cửa hàng, chúng ta chỉ cần làm:

localStorage.clear ();


3
Đây là một câu hỏi 10 năm tuổi. Bạn có nghĩ rằng câu trả lời của bạn thêm bất cứ điều gì chưa được bao phủ bởi các câu trả lời khác không?
Kristopher Johnson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.