Open Lotus1717 opened 5 years ago
mgm库的Storage组件对localStorage的存取方法没有对数据做异常处理导致报错:
set (key, value) { window.localStorage.setItem(prefix + key,JSON.stringify(value)) }, get (key) { const v = window.localStorage.getItem(prefix + key) return v ? JSON.parse(v) : v }
报错场景:
localStorage的键值对总是以字符串的形式存储。对于不是string类型的值,会自动执行toString()方法。然而,对于对象或数组而言,这个转换会丢失它原本的类型信息,导致值在取出的时候不能变为原来的格式。举例: 【例1】localStorage.setItem('a', [1, 2, 3]) 结果:localStorage的键值对依次是‘a'、'1,2,3'
localStorage.setItem('a', [1, 2, 3])
【例2】localStorage.setItem('a', {a: 1}) 结果:ocalStorage的键值对依次是‘a'、'[object, object]'
localStorage.setItem('a', {a: 1})
所以,为了避免在数据转换过程中类型丢失,当我们要存入对象,数组的时候,要以某种编码方式把值做处理,转化为字符串再存进localStorage。这里用到的是JSON数据交换格式。值在存入localStorage前用JSON.stringify方法转化为符合JSON格式的值,从localStorage取出后用JSON.parse方法解析为原来的值。
JSON具有以下形式:
MDN上关于循环引用的对象不可序列化的限制是错的,实际验证了并没有(一开始没有验证,差点信了,还是要多动手试试)。stringify方法内部已经把这个循环引用给过滤了。举例: 【例3】
var A = {a: B, c: 1}, B = {b: A}; JSON.stringify(A);
结果:”{“a”:{“b”:{“c”:1}},”c”:1}”
”{“a”:{“b”:{“c”:1}},”c”:1}”
需要注意的是,对于symbol类型值和undefined,序列化的结果是undefined。但是undefined值在解析的时候会报错,所以在把数据存入localStorage的时候把undefined值过滤掉,避免报错。
关于‘undefined'的序列化处理 JSON.stringify用法: JSON.stringify(value[, replacer [, space]])
JSON.stringify(value[, replacer [, space]])
第二个参数是一个函数,可以在序列化过程中处理被序列化的值的属性。一开始我是想着用这个replacer函数j将’undefined’转换为undefined,这样子序列化的时候自然会把undefined忽略掉。
这也是一开始跟雅堂有争议的地方,‘undefined’这个字符串是不是有意义的,需不需要在序列化的时候过滤掉。我考虑的是值在运行时候的不确定性产生的’undefined‘并非喜闻乐见(想了想,好像自己也很少碰见程序莫名其妙跑出个’undefined‘值),索性把它干掉。雅堂考虑的是从字符串本身出发,它是有意义的。想了想,干预过多并非好事,就像用户的行为由他本身解释,字符串本身也应该自己解释自己才对。而且,程序的值如果是只是单纯的读写的话,更不要随意的手动更改。
不符合JSON规范的值解析会报异常,但传进JSON方法的值是不能在编写代码时确定的,因为JavaScript是一门动态类型语言,变量只有在运行过程中才能确定值的类型。因此,在程序运行过程中JSON.parse方法很可能传入一个非JSON规范的值。所以对于这种可能发生的程序异常,需要使用异常处理机制来防止代码报错,提升程序的容错能力。这里程序的异常处理用到了try catch异常处理机制。序列化和解析数据的代码放在try代码块中,如果有异常数据导致方法报错的话,在catch内部便可以捕捉到程序异常,并打印出警告。
console对象有很多方法属性可以辅助开发的,我经常用console.log方法打印日志,以致于信息不区分轻重全部log,这样容易忽略掉一些值得注意的程序异常。这里是数据异常引发方法运行出错,应该用console.warn方法输出警告信息,提醒开发者报错。
set (key, value) { try { value && window.localStorage.setItem(prefix + key, JSON.stringify(value)) } catch (e) { console.warn(e) } }, get (key) { try { const v = window.localStorage.getItem(prefix + key) return v ? JSON.parse(v) : v } catch (e) { console.warn(e) } }
背景
mgm库的Storage组件对localStorage的存取方法没有对数据做异常处理导致报错:
报错场景:
解决思路
如何处理localStorage
localStorage的键值对总是以字符串的形式存储。对于不是string类型的值,会自动执行toString()方法。然而,对于对象或数组而言,这个转换会丢失它原本的类型信息,导致值在取出的时候不能变为原来的格式。举例: 【例1】
localStorage.setItem('a', [1, 2, 3])
结果:localStorage的键值对依次是‘a'、'1,2,3'【例2】
localStorage.setItem('a', {a: 1})
结果:ocalStorage的键值对依次是‘a'、'[object, object]'所以,为了避免在数据转换过程中类型丢失,当我们要存入对象,数组的时候,要以某种编码方式把值做处理,转化为字符串再存进localStorage。这里用到的是JSON数据交换格式。值在存入localStorage前用JSON.stringify方法转化为符合JSON格式的值,从localStorage取出后用JSON.parse方法解析为原来的值。
关于JSON
JSON具有以下形式:
MDN上关于循环引用的对象不可序列化的限制是错的,实际验证了并没有(一开始没有验证,差点信了,还是要多动手试试)。stringify方法内部已经把这个循环引用给过滤了。举例: 【例3】
结果:
”{“a”:{“b”:{“c”:1}},”c”:1}”
需要注意的是,对于symbol类型值和undefined,序列化的结果是undefined。但是undefined值在解析的时候会报错,所以在把数据存入localStorage的时候把undefined值过滤掉,避免报错。
关于‘undefined'的序列化处理 JSON.stringify用法:
JSON.stringify(value[, replacer [, space]])
第二个参数是一个函数,可以在序列化过程中处理被序列化的值的属性。一开始我是想着用这个replacer函数j将’undefined’转换为undefined,这样子序列化的时候自然会把undefined忽略掉。
这也是一开始跟雅堂有争议的地方,‘undefined’这个字符串是不是有意义的,需不需要在序列化的时候过滤掉。我考虑的是值在运行时候的不确定性产生的’undefined‘并非喜闻乐见(想了想,好像自己也很少碰见程序莫名其妙跑出个’undefined‘值),索性把它干掉。雅堂考虑的是从字符串本身出发,它是有意义的。想了想,干预过多并非好事,就像用户的行为由他本身解释,字符串本身也应该自己解释自己才对。而且,程序的值如果是只是单纯的读写的话,更不要随意的手动更改。
try catch
不符合JSON规范的值解析会报异常,但传进JSON方法的值是不能在编写代码时确定的,因为JavaScript是一门动态类型语言,变量只有在运行过程中才能确定值的类型。因此,在程序运行过程中JSON.parse方法很可能传入一个非JSON规范的值。所以对于这种可能发生的程序异常,需要使用异常处理机制来防止代码报错,提升程序的容错能力。这里程序的异常处理用到了try catch异常处理机制。序列化和解析数据的代码放在try代码块中,如果有异常数据导致方法报错的话,在catch内部便可以捕捉到程序异常,并打印出警告。
关于console
console对象有很多方法属性可以辅助开发的,我经常用console.log方法打印日志,以致于信息不区分轻重全部log,这样容易忽略掉一些值得注意的程序异常。这里是数据异常引发方法运行出错,应该用console.warn方法输出警告信息,提醒开发者报错。
最终代码