你不容错过的JavaScript高级语法(JSON细析, 浏览器数据存储)

简介: 你不容错过的JavaScript高级语法(JSON细析, 浏览器数据存储)

下面一篇文章将介绍JSON, 浏览器数据存储。


JSON


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数据。


  • 项目的某些配置文件。


  • 非关系型数据库(NoSQL)将json作为存储格式。


JSON存储类型


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


  • 简单值:数字(Number)、字符串(String,不支持单引号)、布尔类型(Boolean)、null类型。


123


  • 对象值:由key、value组成,key是字符串类型,并且必须添加双引号,值可以是简单值、对象值、数组值。


{
  "name": "zh",
  "age": 22
}


  • 数组值:数组的值可以是简单值、对象值、数组值。


[
      "abc",
      123,
      {
        "name": "zh"
      }
    ]


JSON序列化


某些情况下我们希望将JavaScript中的复杂类型转化成JSON格式的字符串,这样方便对其进行处理:


将一个对象保存到localStorage中。但是如果我们直接存放一个对象,这个对象会被转化成 [object Object] 格式的字符串,并不是我们想要的结果。


JSON序列化方法


遇到上面的情况,我们就需要使用到JSON的方法进行转化。


在ES5中引用了JSON全局对象,该对象有两个常用的方法:


  • stringify方法:将JavaScript类型转成对应的JSON字符串。


  • parse方法:解析JSON字符串,转回对应的JavaScript类型。


const obj = {
      name: "zh",
      age: 22,
    }
    // 将obj转成JSON格式的字符串
    const objString = JSON.stringify(obj)
    // 将对象数据存储localStorage
    localStorage.setItem("obj", objString)
    const jsonString = localStorage.getItem("obj")
    // 将JSON格式的字符串转回对象
    const info = JSON.parse(jsonString)
    console.log(info)


stringify


其中stringify可以传入第二个参数。


  • 主要是用于定制转化的json字符串。


  • 如果是一个 replacer 函数,可以定制传入对象中的值。


const obj = {
      name: 'zh',
      age: 22,
      friends: ["llm", "zhllm"]
    }
    console.log(JSON.stringify(obj,(key, value) => {
      if(key === "name") {
      // value为当前key的值
        return "llm"
      }else if(key === "age") {
        return 21
      }
      // 其他情况返回原本值
      return value
    })) // {"name":"llm","age":21,"friends":["llm","zhllm"]}


  • 如果指定是数组,则将指定传入的对象那些属性需要转化,其他的忽略。


const obj = {
      name: 'zh',
      age: 22,
      friends: ["llm", "zhllm"]
    }
    console.log(JSON.stringify(obj, ["name", "age"])) //{"name":"zh","age":22}


并且stringify还可以传入第三个参数:


  • 用于格式化数据。


  • 如果传入的是Number类型,那么表示每个key都要空number个空格。格式化数据。


const jsonString = JSON.stringify(obj, null, 2)
    console.log(jsonString)


网络异常,图片无法展示
|


  • 如果传入的是String类型,那么表示每个key前面都会被添加的string代替。格式化数据。


const jsonString = JSON.stringify(obj, null, "---")
    console.log(jsonString)


网络异常,图片无法展示
|


如果说传入的对象内部有toJSON方法,那么stringify方法直接返回toJSON方法返回的值。


const obj = {
      name: 'zh',
      age: 22,
      friends: ["llm", "zhllm"],
      toJSON: function() {
        return "Llm love zh."
      }
    }
    const jsonString4 = JSON.stringify(obj)
    console.log(jsonString4) //"Llm love zh."


parse


parse方法也能传递第二个参数。为一个函数,用来定制转化后的值。


const JSONString = `{
      "name": "zh",
      "age": 22,
      "friends": [
        "llm",
        "zhllm"
      ]
    }`
    const info = JSON.parse(JSONString, (key, value) => {
      if (key === "age") {
        return value - 1
      }
      return value
    })
    console.log(info) //{ name: 'zh', age: 21, friends: [ 'llm', 'zhllm' ] }


使用JSON序列化深拷贝


另外我们生成的新对象和之前的对象并不是同一个对象。相当于是进行了一次深拷贝。


const obj = {
      name: 'zh',
      age: 22,
      friends: ["llm", "zhllm"],
      person: {
        name: 'pp'
      },
      foo: function() {
        console.log("foo function")
      }
    }
    const obj1 = JSON.parse(JSON.stringify(obj))
    console.log(obj1.person === obj.person) // false


注意:这种方法它对函数是无能为力的。因为stringify并不会对函数进行处理。


浏览器数据存储


Storage


WebStorage主要提供了一种机制,可以让浏览器提供一种比cookie更直观的key、value存储方式:


  • localStorage:本地存储,提供的是一种永久性的存储方法,在关闭掉网页重新打开时,存储的内容依然保留。


  • sessionStorage:会话存储,提供的是本次会话的存储,在关闭掉会话时,存储的内容会被清除。 localStorage和sessionStorage的区别:


  • 关闭网页后重新打开,localStorage会保留,而sessionStorage会被删除。


  • 在页面内实现跳转,localStorage会保留,sessionStorage也会保留。


  • 在页面外实现跳转(打开新的网页),localStorage会保留,sessionStorage不会被保留。 Storage常见的方法和属性:


  • Storage.length:只读属性


  • 返回一个整数,表示存储在Storage对象中的数据项数量。


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


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


  • Storage.setItem():该方法接受一个key和value,并且将会把key和value添加到存储中。如果key存储,则更新其对应的值。


  • Storage.removeItem():该方法接受一个key作为参数,并把该key从存储中删除。


  • Storage.clear():该方法的作用是清空存储中的所有key。 下面来对localStorage和sessionStorage进行封装并对其进行JSON序列化,方便以后使用:


class Cache {
      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
        } 
      }
      removeItem(key) {
        this.storage.removeItem(key)
      }
      clear() {
        this.storage.clear()
      }
      key(index) {
        return this.storage.key(index)
      }
      length() {
        return this.storage.length
      }
    }
    const localCache = new Cache()
    const sessionCache = new Cache(false)
    export {
      localCache,
      sessionCache
    }


IndexedDB


什么是IndexedDB呢?


我们能看到DB这个词,就说明它其实是一种数据库(Database),通常情况下在服务器端比较常见。在实际的开发中,大量的数据都是存储在数据库的,客户端主要是请求这些数据并且展示。


有时候我们可能会存储一些简单的数据到本地(浏览器中),比如token、用户名、密码、用户信息等,比较少存储大量的数据。那么如果确实有大量的数据需要存储,这个时候可以选择使用IndexedDB。


  • IndexedDB是一种底层的API,用于在客户端存储大量的结构化数据。


  • 它是一种事务型数据库系统,是一种基于JavaScript面向对象数据库,有点类似于NoSQL(非关系型数据库)。


  • IndexDB本身就是基于事务的,我们只需要指定数据库模式,打开与数据库的连接,然后检索和更新一系列事务即可。


IndexedDB的连接数据库


第一步:打开indexedDB的某一个数据库:


  • 通过indexDB.open(数据库名称, 数据库版本)方法。


  • 如果数据库不存在,那么会创建这个数据。


  • 如果数据库已经存在,那么会打开这个数据库。


// 打开数据(和数据库建立连接)
    const dbRequest = indexedDB.open("zhDB", 2)


第二步:通过监听回调得到数据库连接结果:


  • 数据库的open方法会得到一个IDBOpenDBRequest类型


  • 我们可以通过下面的三个回调来确定结果:


  • onerror:当数据库连接失败时。


  • onsuccess:当数据库连接成功时回调。我们可以通过onsuccess回调的event获取到db对象:event.target.result。


  • onupgradeneeded:当数据库第一次打开或者version发生变化并且高于之前版本时回调。通常我们在这里会创建具体的存储对象:db.createObjectStore(存储对象名称, { keypath: 存储的主键 })


dbRequest.onerror = function(err) {
      console.log("打开数据库失败~")
    }
    // 以后访问时的回调
    let db = null
    dbRequest.onsuccess = function(event) {
      db = event.target.result
    }
    // 第一次打开/或者版本发生升级
    dbRequest.onupgradeneeded = function(event) {
      const db = event.target.result
      // 创建一些存储对象
      db.createObjectStore("users", { keyPath: "id" })
    }


IndexedDB的数据库操作


我们对数据库的操作要通过事务对象来完成:


  • 第一步:通过db获取对应存储的事务 db.transaction(存储名称, 可写操作)。


  • 第二步:通过事务获取对应的存储对象 transaction.objectStore(存储名称)。


const transaction = db.transaction("users", "readwrite")
    const store = transaction.objectStore("users")


接下来我们就可以进行增删改查操作了:


  • 增。通过add方法。


const request = store.add(user)
    // 单条数据存储成功后的回调
    request.onsuccess = function() {
        console.log(`${user.name}插入成功`)
    }
    // 全部数据存储成功的回调。
    transaction.oncomplete = function() {
      console.log("添加操作全部完成")
    }


  • 查。


  • 方式一:get方法,只能传入主键, 根据主键查询。


  • 方式二:openCursor方法,然后调用成功时的回调,然后查询全部数据,然后if过滤数据。


// 方式一
    const request = store.get(102)
    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("查询完成")
      }
    }


  • 改。还是先查找,然后调用该记录的update方法。将修改后的数据作为参数传入。


const updateRequest = store.openCursor()
    updateRequest.onsuccess = function(event) {
      const cursor = event.target.result
      if (cursor) {
        if (cursor.key === 101) {
          const value = cursor.value;
          value.name = "curry"
          cursor.update(value)
        } else {
          cursor.continue()
        }
      } else {
        console.log("查询完成")
      }
    }


  • 删。还是先查找,然后调用该记录的delete方法。


const deleteRequest = store.openCursor()
    deleteRequest.onsuccess = function(event) {
      const cursor = event.target.result
      if (cursor) {
        if (cursor.key === 101) {
          cursor.delete()
        } else {
          cursor.continue()
        }
      } else {
        console.log("查询完成")
      }
    }


详细知识请访问mdn下面来看一下案例


<button>新增</button>
  <button>查询</button>
  <button>删除</button>
  <button>修改</button>
  <script src="./index.js"></script>


// 打开数据(和数据库建立连接)
    const dbRequest = indexedDB.open("zhDB", 3)
    dbRequest.onerror = function(err) {
      console.log("打开数据库失败~")
    }
    let db = null
    dbRequest.onsuccess = function(event) {
      db = event.target.result
    }
    // 第一次打开/或者版本发生升级
    dbRequest.onupgradeneeded = function(event) {
      const db = event.target.result
      console.log(db)
      // 创建一些存储对象
      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, "zh", 18),
      new User(101, "llm", 40),
      new User(102, "zh-llm", 30),
    ]
    // 获取btns, 监听点击
    const btns = document.querySelectorAll("button")
    for (let i = 0; i < btns.length; i++) {
      btns[i].onclick = function() {
        const transaction = db.transaction("users", "readwrite")
        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:
            console.log("点击了查询")
            // 1.查询方式一(知道主键, 根据主键查询)标识要检索的记录的键或键范围。
            const request = store.get(102)
            request.onsuccess = function(event) {
              console.log(event.target.result)
            }
            // 2.查询方式二:
            // 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:
            console.log("点击了删除")
            const deleteRequest = store.openCursor()
            deleteRequest.onsuccess = function(event) {
              const cursor = event.target.result
              if (cursor) {
                if (cursor.key === 101) {
                  cursor.delete()
                } else {
                  cursor.continue()
                }
              } else {
                console.log("查询完成")
              }
            }
            break
          case 3:
            console.log("点击了修改")
            const updateRequest = store.openCursor()
            updateRequest.onsuccess = function(event) {
              const cursor = event.target.result
              if (cursor) {
                if (cursor.key === 101) {
                  const value = cursor.value;
                  value.name = "curry"
                  cursor.update(value)
                } else {
                  cursor.continue()
                }
              } else {
                console.log("查询完成")
              }
            }
            break
        }
      }
    }


网络异常,图片无法展示
|



相关文章
|
3月前
|
存储 JavaScript 前端开发
Node.js的基本语法
【8月更文挑战第12天】Node.js的基本语法
113 1
|
8天前
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
13天前
|
JavaScript 前端开发 大数据
在JavaScript中,Object.assign()方法或展开语法(...)来合并对象,Object.freeze()方法来冻结对象,防止对象被修改
在JavaScript中,Object.assign()方法或展开语法(...)来合并对象,Object.freeze()方法来冻结对象,防止对象被修改
10 0
|
2月前
|
JSON 前端开发 JavaScript
java中post请求调用下载文件接口浏览器未弹窗而是返回一堆json,为啥
客户端调接口需要返回另存为弹窗,下载文件,但是遇到的问题是接口调用成功且不报错,浏览器F12查看居然返回一堆json,而没有另存为弹窗; > 正确的效果应该是:接口调用成功且浏览器F12不返回任何json,而是弹窗另存为窗口,直接保存文件即可。
112 2
|
3月前
|
JavaScript 前端开发
JavaScript基础&实战(1)js的基本语法、标识符、数据类型
这篇文章是JavaScript基础与实战教程的第一部分,涵盖了JavaScript的基本语法、标识符、数据类型以及如何进行强制类型转换,通过代码示例介绍了JS的输出语句、编写位置和数据类型转换方法。
JavaScript基础&实战(1)js的基本语法、标识符、数据类型
|
3月前
|
存储 前端开发 JavaScript
揭秘!JavaScript本地存储的四大绝技:从Cookie到IndexedDB,让你的Web应用秒变数据存储高手,轻松应对各种挑战!
【8月更文挑战第4天】JavaScript为核心前端技术,提供多样本地存储方案以优化用户体验与减少服务器负载。首先,Cookie虽用于基本数据如登录状态,但受大小限制及安全性影响。接着,Web Storage中的LocalStorage持久存储不变数据,SessionStorage则限于单次会话。更进一步,IndexedDB作为全面数据库解决方案,支持复杂数据操作但使用较复杂。每种方式根据应用需求各有优势。
56 9
|
3月前
|
前端开发 JavaScript 程序员
前端 JavaScript 的 _ 语法是个什么鬼?
前端 JavaScript 的 _ 语法是个什么鬼?
|
4月前
|
缓存 JavaScript 前端开发
前端框架与库 - Vue.js基础:模板语法、数据绑定
【7月更文挑战第14天】Vue.js 是渐进式框架,以简洁API和高效数据绑定知名。本文聚焦模板语法与数据绑定,解释常见问题和易错点,助力初学者避坑。模板语法中,{{ expression }} 用于渲染值,v-bind/: 用于动态绑定属性。数据绑定涉及文本、属性和事件,注意v-model适用于表单元素,计算属性有缓存。理解正确用法,借助文档和IDE,可提升开发质量和效率。善用Vue.js,打造响应式UI。
118 4
|
5月前
|
前端开发 JavaScript 安全
高级前端开发需要知道的 25 个 JavaScript 单行代码
1. 不使用临时变量来交换变量的值 2. 对象解构,让数据访问更便捷 3. 浅克隆对象 4. 合并对象 5. 清理数组 6. 将 NodeList 转换为数组 7. 检查数组是否满足指定条件 8. 将文本复制到剪贴板 9. 删除数组重复项 10. 取两个数组的交集 11. 求数组元素的总和 12. 根据指定条件判断,是否给对象的属性赋值 13. 使用变量作为对象的键 14. 离线状态检查器 15. 离开页面弹出确认对话框 16. 对象数组,根据对象的某个key求对应值的总和 17. 将 url 问号后面的查询字符串转为对象 18. 将秒数转换为时间格式的字符串 19.
58 3
高级前端开发需要知道的 25 个 JavaScript 单行代码
|
5月前
|
存储 JavaScript 前端开发
JavaScript 语法
JavaScript 语法
34 5