JSON数据存储和浏览器数据存储

一、JSON

1.JSON的由来

  • 在目前的开发中,JSON是一种非常重要的数据格式,它并不是编程语言,而是一种可以在服务器和客户端之间传输的数据格式。

  • JSON的全称是 JavaScript Object Notation(JavaScript对象符号):

    • JSON是由Douglas Crockford构想和设计的一种轻量级资料交换格式,算是JavaScript的一个子集。
    • 但是虽然JSON被提出来的时候是主要应用JavaScript中,但是目前已经独立于编程语言,可以在各个编程语言中使用。
    • 很多编程语言都实现了将JSON转成对应模型的方式。
  • 其他的传输格式:

    • XML:在早期的网络传输中主要是使用XML来进行数据交换的,但是这种格式在解析、传输等各方面都弱于JSON,所以目前已经很少在被使用了。
    • Protobuf:另外一个在网络传输中目前已经越来越多使用的传输格式是protobuf,但是直到2021年的3.x版本才支持JavaScript,所以目前在前端使用的较少。
  • 目前JSON被使用的应用场景也越来越多

    • 网络数据的传输JSON数据。
    • 项目的某些配置文件。
      • 小程序的 app.json文件
    • 非关系型数据库(NoSQL)将json作为存储格式。

2.JSON的基本语法

  • JSON文件的后缀名是.json

  • JSON的顶层支持三种类型的值:

    • 简单值:数字(Number)、字符串(String,不支持单引号)、布尔类型(Boolean)、null类型
    • 对象值:由key、value组成,key是字符串类型,并且必须添加双引号,值可以是简单值、对象值、数组值
    • 数组值:数组的值可以是简单值、对象值、数组值。
  • JSON不能有注释

  • JSON不能有多余的逗号

3.JSON序列化

  • 某些情况下我们希望将JavaScript中复杂类型转化成JSON格式的字符串,这样方便对其进行处理。
    • 比如我们希望将一个对象保存到localStorage中
    • 但是如果我们直接存放一个对象,这个对象会被转化成 [object Object]格式的字符串,并不是我们想要的结果。
const obj={
  name:"wjy",
  age:18,
  friends:{
    name:"hyz"
  },
  hobbies:["篮球","足球"]
}

// 将对象数据存储在localStorage中
// * 因为localStorage的第二个参数也是需要传字符串类型,所以会先将对象类型转化为string类型 
localStorage.setItem("obj",obj);

// * 取出存储的值
console.log(localStorage.getItem("obj"));//[object Object]

在浏览器中的 显示 [object Object]

image-20220522203839374.png
  • 通过JSON.stringify()将对象转化为JSON字符串。
  • 通过JSON.parse()将JSON字符串解析为一个对象

3.1 序列化JSON.stringify的细节

  • 可以传入第二个参数

    • 可以是数组
      • 在数组可以指定哪些属性需要进行转换
    • 也可以是一个回调函数
      • 会回调每个key-value
  • 也可以传入第三个参数

    • 是对字符串进行美化
    • 可以传入数字或字符串
      • 数字n:会在key使用n个空格
      • 字符串:会在key前面添加传入的字符串
const obj={
  name:"wjy",
  age:18,
  friends:{
    name:"hyz"
  },
  hobbies:["篮球","足球"],
}

// * 需求:将上面的对象转成JSON字符串
// * 1. 直接转化
const jsonString1=JSON.stringify(obj)

console.log(jsonString1); // {"name":"wjy","age":18,"friends":{"name":"hyz"},"hobbies":["篮球","足球"]}

// * 2.stringify第二个参数replacer
// * 2.1 传入数组:设定哪些是需要转换的。
const jsonString2=JSON.stringify(obj,["name","friends"])
console.log(jsonString2);// {"name":"wjy","friends":{"name":"hyz"}}

// * 2.2 传入一个回调函数:会遍历每个key value
// 年龄虚岁要加1
const jsonString3=JSON.stringify(obj,(key,value)=>{
  if(key=="age") return value+1;
  return value;
})

console.log(jsonString3);//{"name":"wjy","age":19,"friends":{"name":"hyz"},"hobbies":["篮球","足球"]}

// *3 stringify有第三个参数 space:可以是数字或者字符串
const jsonString4=JSON.stringify(obj,null,2)
console.log(jsonString4);

// {
//   "name": "wjy",
//   "age": 18,
//   "friends": {
//     "name": "hyz"
//   },
//   "hobbies": [
//     "篮球",
//     "足球"
//   ]
// }

// * 4.如果转换的对象有toJSON这个函数,会直接使用这个函数的返回值
// const jsonString5=JSON.stringify(obj);
// console.log(jsonString5);

3.2 序列化JSON.parse细节

  • 它可以传入第二个参数
    • 一个回调函数,可以进行对key-value进行拦截
const JSONString='{"name":"wjy","age":19,"friends":{"name":"hyz"},"hobbies":["篮球","足球"]}';

// * 第二个参数可以对值进行拦截
const info=JSON.parse(JSONString,(key,value)=>{
  if(key=="age") return value-1;
  return value
});
console.log(info);

3.3 实现深拷贝

  • 赋值:引用的是同一片空间
  • 浅拷贝:只是拷贝第一层属性的值
  • 深拷贝:两个对象之间完全没有关系,JSON.stringify和JSON.parse实现深拷贝存在一些缺陷
const obj={
  name:"wjy",
  age:18,
  friends:{
    name:"hyz"
  },
  hobbies:["篮球","足球"],
  foo(){
    console.log("foo函数");
  }
}

// * 将obj对象的内容放到info变量中
// * 1. 引用赋值
const info=obj


// * 浅拷贝:只是将里面的属性拷贝了一份,

/**
 * * Object.assign()
 */
const info2={...obj};
console.log(info2==obj); //false
info2.age=100;
console.log("obj的age:",obj.age);
info2.hobbies[0]="吃零食";
console.log("obj的hobbies:",obj.hobbies);

// * 深拷贝 :让两个对象完全没有关系 
// * 使用JSON.stringify和JSON.parse,但是对函数是无能为力的
const info3=JSON.parse(JSON.stringify(obj))
info3.friends.name="tqy";
console.log(obj.friends.name);
console.log(info3);

二、浏览器的存储方案

1.认识Storage

  • WebStorage主要提供了一种机制,可以让浏览器提供一种比cookie更直观的key、value存储方式:
    • localStorage:本地存储,提供的是一种永久性的存储方法,在关闭掉网页重新打开时,存储的内容依然保留。
    • sessionStorage:会话存储,提供的是本次会话的存储,在关闭掉会话时,存储的内容会被清除。
image-20220522232723625.png

1.1 localStorage和sessionStorage有什么区别

  • 我们会发现localStorage和sessionStorage看起来非常的相似。
  • 那么它们有什么区别呢?
    • 验证一:关闭网页后重新打开,localStorage会保留,sessionStorage不会保留
    • 验证二:在页面内实现跳转,localStorage会保留,sessionStorage也会保留
    • 验证三:在页面外实现跳转(打开新的网页),localStorage会保留,sessionStorage不会保留。

1.2 Storage常见的方法和属性

适用于localStorage和sessionStorage

Storage具有如下的属性和方法

  • 属性

    • Storage.length:只读属性
      • 返回一个整数,表示存储在Storage对象中的数据项数量。
  • 方法

    • Storage.key():该方法接受一个数值n作为参数,返回存储中第n个key名称。

    • Storage.getItem():该方法接受一个key作为参数,并且返回key对应的value。

    • Storage.setItem():该方法接受一个key和value,并且将会key和value添加到存储中。

      • 如果key存储,则更新对应的值。
    • Storage.removeItem():该方法接受一个key作为参数,并把该key对应的value从存储中删除。

    • Storage.clear():该方法的作用是清空存储中的所有key。

1.3 封装Storage

class JYCache{
  constructor(isLocal=true){
    this.storage=isLocal?localStorage:sessionStorage;
  }

  setItem(key,value){
    if(value){
      this.storage.setItem(key,JSON.stringify(value))
    }
  }

  getItem(key){
    let value=this.storage.getItem(key);
    if(value){
      value=JSON.parse(value);
    }
    return value;
  }

  key(index){
    return this.storage.key(index);
  }

  removeItem(key){
    this.storage.removeItem(key);
  }

  length(){
    return this.storage.length;
  }

}

const localCache=new JYCache();
const sessionCache=new JYCache(false);

export {
  localCache,
  sessionCache
}

2. IndexedDB

  • 什么是IndexDB呢?

    • 我们能看到DB这个词,就说明它其实是一种数据库(Database),通常情况下在服务器端比较常见。
    • 在实际的开发中,大量的数据都是存储在数据库的,客户端主要是请求这些数据并且展示。
    • 有时候我们可能会存储一些简单的数据到本地(浏览器中),比如token、用户名、密码、用户信息等,比较少存储大量的数据。
    • 那么如果确实有大量的数据需要存储,这个时候可以选择使用IndexDB
  • IndexedDB是一种底层的API用于在客户端存储大量的结构化数据

    • 它是一种事务型数据库系统,是一种基于JavaScript面向对象数据库,有点类似于NoSQL(非关系型数据库)
      • 事务是对数据库进行操作的时候一个操作单元
    • IndexDB本身就是基于事务的,我们只需要指定数据库模式,打开与数据库的连接,然后检索和更新一系列事务即可。

key是一个个数值型,value是一个个对象

2.1 IndexedDB的连接数据库

  • 第一步:打开indexedDB的某一个数据库。
    • 通过indexedDB.open(数据库名称,数据库版本)方法。
    • 如果数据库不存在,那么会创建这个数据库。
    • 如果数据库已经存在,那么会打开这个数据库。
// * 打开数据库,和数据库建立连接
// * 有wjy数据库就打开,没有就会创建。
const dbRequest=indexedDB.open("wjy",2)
let db=null;
// * 数据库连接失败
dbRequest.onerror=function(err){
  console.log("数据库连接失败");
}

dbRequest.onsuccess=function(event){
  db=event.target.result;
  // console.log("数据库连接成功");
}

// * 第一次打开 或者版本发生更新
dbRequest.onupgradeneeded=function(event){
  const db=event.target.result;

  // * 创建一些存储对象
  // * keyPath:设置表的主键 ,例如users的主键是id
  db.createObjectStore("users",{keyPath:"id"})
}

class User{
  constructor(id,name,age){
    this.id=id;
    this.name=name;
    this.age=age;
  }
}

const users=[
  new User(100,"wjy",20),
  new User(101,"hyz",20),
  new User(102,"tqy",20),
]

// 获取btns ,监听点击
const btns=document.querySelectorAll("button")
for(let i=0;i<btns.length;i++){
  btns[i].onclick=function(){
    console.log("db:",db);
    // * 创建一个事务
    const transaction=db.transaction(["users"],"readwrite")
    console.log("transaction:",transaction);
    // * 获取一个具体的store对象
    const store=transaction.objectStore("users");
    switch(i){
      case 0:
        console.log("点击了新增");
        for(const user of users){
          const request=store.add(user);
          request.onsuccess=function(){
            console.log(`${user.name}插入成功`);
          }
        }
        transaction.oncomplete=function(){
          console.log("添加操作全部完成");
        }
        break;
      case 1:
        // * 查询方式一:store.get() (知道主键,根据主键查询)
        // console.log("点击了查询");
        // const request=store.get(100);
        // request.onsuccess=function(event){
        //   console.log(event.target.result);
        // }

        // * 查询方式二
        const request=store.openCursor()
       request.onsuccess=function(event){
         const cursor=event.target.result;
         if(cursor){
           if(cursor.key==101)
           {
            console.log(cursor.key,cursor.value);
           }else cursor.continue()
         }else{
           console.log("查询完成");
         }
       }
        break;
      case 2:
        const request2=store.openCursor()
        request2.onsuccess=function(event){
          const cursor=event.target.result;
          if(cursor){
            if(cursor.key==101)
            {
              cursor.delete()
            }else cursor.continue()
          }else{
            console.log("查询完成");
          }
        }
        console.log("点击了删除");
        break;
      case 3:
        const deleteRequest=store.openCursor()
        deleteRequest.onsuccess=function(event){
          const cursor=event.target.result;
          if(cursor){
            if(cursor.key==101)
            {
              const value=cursor.value;
              value.name="curry"
              cursor.update(value)
             console.log(cursor.key,cursor.value);
            }else cursor.continue()
          }else{
            console.log("查询完成");
          }
        }
        console.log("点击了修改");
        break;
    }
  }
}

三、总结

JSON的数据存储和浏览器的数据存储.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容