Kri*_*son 2386 javascript html5 local-storage
我想在HTML5中存储JavaScript对象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);
Run Code Online (Sandbox Code Playgroud)
控制台输出是
typeof testObject: object
testObject properties:
one: 1
two: 2
three: 3
typeof retrievedObject: string
Value of retrievedObject: [object Object]
Run Code Online (Sandbox Code Playgroud)
在我看来,该setItem
方法是在存储之前将输入转换为字符串.
我在Safari,Chrome和Firefox中看到了这种行为,因此我认为这是我对HTML5 Web存储规范的误解,而不是特定于浏览器的错误或限制.
我试图理解http://www.w3.org/TR/html5/infrastructure.html中描述的结构化克隆算法.我不完全理解它的含义,但也许我的问题与我的对象的属性不可枚举(???)
有一个简单的解决方法吗?
更新:W3C最终改变了对结构化克隆规范的看法,并决定更改规范以匹配实现.请参阅https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111.所以这个问题不再是100%有效,但答案仍然可能是有意义的.
CMS*_*CMS 3036
查看Apple,Mozilla和Microsoft文档,该功能似乎仅限于处理字符串键/值对.
解决方法可以是在存储对象之前对其进行字符串化,然后在检索对象时对其进行解析:
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));
Run Code Online (Sandbox Code Playgroud)
Gur*_*ria 608
对变体的微小改进:
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);
}
Run Code Online (Sandbox Code Playgroud)
由于短路评估,如果不在存储中getObject()
则会立即返回.如果是(空字符串; 无法处理),它也不会抛出异常.null
key
SyntaxError
value
""
JSON.parse()
小智 213
您可能会发现使用这些方便的方法扩展Storage对象很有用:
Storage.prototype.setObject = function(key, value) {
this.setItem(key, JSON.stringify(value));
}
Storage.prototype.getObject = function(key) {
return JSON.parse(this.getItem(key));
}
Run Code Online (Sandbox Code Playgroud)
这样您就可以获得您真正想要的功能,即使API下面只支持字符串.
Ale*_*nde 71
扩展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;
}
}
Run Code Online (Sandbox Code Playgroud)
maj*_*aja 62
似乎这里的答案并未涵盖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"
Run Code Online (Sandbox Code Playgroud)
我不建议存储函数,因为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);
Run Code Online (Sandbox Code Playgroud)
另一个问题stringify
是无法处理循环引用:
var obj = {};
obj["circular"] = obj;
localStorage.object = JSON.stringify(obj); //Fails
Run Code Online (Sandbox Code Playgroud)
在此示例中,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;
}
});
Run Code Online (Sandbox Code Playgroud)
但是,找到一个有效的存储循环引用的解决方案很大程度上取决于需要解决的任务,恢复这些数据也不是一件容易的事.
在处理这个问题的SO上已经存在一些问题:Stringify(转换为JSON)一个带有循环引用的JavaScript对象
JPr*_*mer 51
有一个很棒的库包含许多解决方案,所以它甚至支持称为jStorage的旧浏览器
您可以设置一个对象
$.jStorage.set(key, value)
Run Code Online (Sandbox Code Playgroud)
并轻松检索它
value = $.jStorage.get(key)
value = $.jStorage.get(key, "default value")
Run Code Online (Sandbox Code Playgroud)
小智 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;
}
Run Code Online (Sandbox Code Playgroud)
但是,函数序列化/反序列化是不可靠的,因为它依赖于实现.
小智 23
如果没有字符串格式,则无法存储键值。
LocalStorage仅支持键/值的字符串格式。
这就是为什么您应该将数据转换为字符串,无论它是数组还是对象。
To store data in localStorage, first of all stringify it using the JSON.stringify() method.
var myObj = [{name:"test", time:"Date 2017-02-03T08:38:04.449Z"}];
localStorage.setItem('item', JSON.stringify(myObj));
Run Code Online (Sandbox Code Playgroud)
Then when you want to retrieve data, you need to parse the string to object again.
var getObj = JSON.parse(localStorage.getItem('item'));
Run Code Online (Sandbox Code Playgroud)
And*_*enz 21
在点击另一个已经关闭的帖子后,我到达了这个帖子,这个帖子的标题是"如何在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);
}
Run Code Online (Sandbox Code Playgroud)
示例用法 - 在localStorage数组中存储简单字符串:
localStorage.pushArrayItem('myArray','item one');
localStorage.pushArrayItem('myArray','item two');
Run Code Online (Sandbox Code Playgroud)
示例用法 - 在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);
Run Code Online (Sandbox Code Playgroud)
操作数组的常用方法:
.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
Run Code Online (Sandbox Code Playgroud)
dou*_*osh 13
建议使用抽象库来实现此处讨论的许多功能以及更好的兼容性.很多选择:
您可以使用ejson将对象存储为字符串。
EJSON 是 JSON 的扩展以支持更多类型。它支持所有 JSON 安全类型,以及:
- 日期 (JavaScript
Date
)- 二进制(JavaScript
Uint8Array
或EJSON.newBinary的结果)- 用户定义的类型(参见EJSON.addType。例如,Mongo.ObjectID就是这样实现的。)
所有 EJSON 序列化也是有效的 JSON。例如,带有日期和二进制缓冲区的对象将在 EJSON 中序列化为:
Run Code Online (Sandbox Code Playgroud){ "d": {"$date": 1358205756553}, "b": {"$binary": "c3VyZS4="} }
这是我使用 ejson 的 localStorage 包装器
https://github.com/UziTech/storage.js
我在包装器中添加了一些类型,包括正则表达式和函数
您可以使用localDataStorage透明地存储javascript数据类型(Array,Boolean,Date,Float,Integer,String和Object).它还提供轻量级数据混淆,自动压缩字符串,便于按键(名称)查询以及按(键)值查询,并通过为键添加前缀来帮助在同一域内强制执行分段共享存储.
[免责声明]我是该实用程序的作者[/ DISCLAIMER]
例子:
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
Run Code Online (Sandbox Code Playgroud)
如您所见,原始值受到尊重.
对于愿意设置和获取类型属性的 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);
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
// 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");
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1010270 次 |
最近记录: |