WebStorage主要提供了一种机制,可以让浏览器提供一种比cookie更直观的key、value存储方式:
localStorage
:本地存储,提供的是一种永久性的存储方法
,在关闭掉网页重新打开时,存储的内容依然保留;sessionStorage
:会话存储,提供的是本次会话的存储
,在关闭掉会话时,存储的内容会被清除;localStorage.setItem("name", "local");
sessionStorage.setItem("name", "session");
我们会发现localStorage和sessionStorage看起来非常的相似。
那么它们有什么区别呢?
Storage有如下的属性和方法:
属性:
Storage.length:只读属性
方法:
Storage.key():该方法接受一个数值n作为参数,返回存储中的第n个key名称;
Storage.getItem():该方法接受一个key作为参数,并且返回key对应的value;
Storage.setItem():该方法接受一个key和value,并且将会把key和value添加到存储中。
Storage.removeItem():该方法接受一个key作为参数,并把该key从存储中删除;
Storage.clear():该方法的作用是清空存储中的所有key;
const ACCESS_TOKEN = "token"
console.log(localStorage.length)
// 常见的方法:
localStorage.setItem(ACCESS_TOKEN, "whytoken")
console.log(localStorage.getItem(ACCESS_TOKEN))
// 其他方法
console.log(localStorage.key(0))
console.log(localStorage.key(1))
console.log(localStorage.removeItem("infoTab"))
localStorage.clear()
class Cache {
constructor(isLocal = true) {
this.storage = isLocal ? localStorage: sessionStorage
}
setCache(key, value) {
if (!value) {
throw new Error("value error: value必须有值!")
}
if (value) {
this.storage.setItem(key, JSON.stringify(value))
}
}
getCache(key) {
const result = this.storage.getItem(key)
if (result) {
return JSON.parse(result)
}
}
removeCache(key) {
this.storage.removeItem(key)
}
clear() {
this.storage.clear()
}
}
const localCache = new Cache()
const sessionCache = new Cache(false)
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<script src="./js/cache.js">script>
<script>
localCache.setCache("sno", 111)
// storage本身是不能直接存储对象类型的
const userInfo = {
name: "abc",
nickname: "def",
level: 100,
imgURL: "http://github.com/abc.png"
}
// localStorage.setItem("userInfo", JSON.stringify(userInfo))
// console.log(JSON.parse(localStorage.getItem("userInfo")))
sessionCache.setCache("userInfo", userInfo)
console.log(sessionCache.getCache("userInfo"))
script>
body>
html>
我们先来看一下维基百科对正则表达式的解释:
简单概况:正则表达式是一种字符串匹配
利器,可以帮助我们搜索、获取、替代字符串;
在JavaScript中,正则表达式使用RegExp
类来创建,也有对应的字面量的方式:
const re1 = new RegExp("hello", "i")
const re2 = /hello/i
有了正则表达式我们要如何使用它呢?
// 创建正则
const re1 = /abc/ig
const message = "fdabc123 faBC323 dfABC222 A2324aaBc"
// 1.使用正则对象上的实例方法
// webpack -> loader -> test: 匹配文件名
// 正则 -> 拿到文件 -> loader操作
// 1.1.test方法: 检测某一个字符串是否符合正则的规则
// if (re1.test(message)) {
// console.log("message符合规则")
// } else {
// console.log("message不符合规则")
// }
// 1.2.exec方法: 使用正则执行一个字符串
// const res1 = re1.exec(message)
// console.log(res1)
// 2.使用字符串的方法, 传入一个正则表达式
// 2.1. match方法:
// const result2 = message.match(re1)
// console.log(result2)
// 2.2. matchAll方法
// 注意: matchAll传入的正则修饰符必须加g
// const result3 = message.matchAll(re1)
// // console.log(result3.next())
// // console.log(result3.next())
// // console.log(result3.next())
// // console.log(result3.next())
// for (const item of result3) {
// console.log(item)
// }
// 2.3. replace/replaceAll方法
// 2.4. split方法
// const result4 = message.split(re1)
// console.log(result4)
// 2.5. search方法
const result5 = message.search(re1)
console.log(result5)
// 案例: 让用户输入的账号必须是aaaaa以上
// const inputEl = document.querySelector("input")
// const tipEl = document.querySelector(".tip")
// inputEl.oninput = function() {
// const value = this.value
// if (/^a{5,8}$/.test(value)) {
// tipEl.textContent = "输入的内容符合规则要求"
// } else {
// tipEl.textContent = "输入的内容不符合规则要求, 请重新输入"
// }
// }
常见的修饰符
flag | 含义 |
---|---|
g | 全部的,给我匹配全部的 |
i | 忽略大小写 |
m | 多行匹配 |
需求:
let message = "Hello abc, abc, Abc, AAaBc"
const pattern = /abc/ig
const results = message.match(pattern)
console.log(results)
message = message.replaceAll(pattern, "ABC")
console.log(message)
字符类(Character classes) 是一个特殊的符号,匹配特定集中的任何符号。
字符 | 含义 |
---|---|
\d(“d” 来自 “digit”) | 数字:从 0 到 9 的字符。 |
\s(“s” 来自 “space”) | 空格符号:包括空格,制表符 \t,换行符 \n 和其他少数稀有字符,例如 \v,\f 和 \r。 |
\w(“w” 来自 “word”) | “单字”字符:拉丁字母或数字或下划线 _。 |
.(点) | 点 . 是一种特殊字符类,它与 “除换行符之外的任何字符” 匹配 |
反向类(Inverse classes)
const message = "CSS2.5"
const pattern = /CSS\d(\.\d)?/i
console.log(message.match(pattern))
符号 ^
和符号 $
在正则表达式中具有特殊的意义,它们被称为“锚点”。
文本开头
;文本末尾
;const message = "My name is WHY."
// 字符串方法
if (message.startsWith("my")) {
console.log("以my开头")
}
if (message.endsWith("why")) {
console.log("以why结尾")
}
// 正则: 锚点
if (/^my/i.test(message)) {
console.log("以my开头")
}
if (/why\.$/i.test(message)) {
console.log("以why结尾")
}
const re = /^coder$/
const info = "codaaaer"
console.log(re.test(info)) // false
词边界(Word boundary)
\b
是一种检查,就像 ^ 和 $ 一样,它会检查字符串中的位置是否是词边界
。匹配下面字符串中的时间:
const message = "now time 22:45, number is 123.456"
const timepattern = /\b\d\d:\d\d\b/g
console.log(message.match(timepattern))
如果要把特殊字符作为常规字符来使用,需要对其进行转义
:
反斜杠
;常见的需要转义的字符:
[] \ ^ $ . | ? * + ()
/
并不是一个特殊符号,但是在字面量正则表达式中也需要转义;练习:匹配所有以.js或者jsx结尾的文件名
const filenames = ["abc.js", "cba.java", "nba.html"]
const newNames = filenames.filter(item => {
return /\.jsx?$/.test(item)
})
在webpack当中,匹配文件名时就是以这样的方式。
// 定义正则: 对.转义
const re = /\./ig
const message = "abc.why"
const results = message.match(re)
console.log(results)
// 特殊: /
// const re2 = /\//
// 获取到很多的文件名
// jsx -> js文件
const fileNames = ["abc.html", "Home.jsx", "index.html", "index.js", "util.js", "format.js"]
// 获取所有的js的文件名(webpack)
// x?: x是0个或者1个
const jsfileRe = /\.jsx?$/
// 1.for循环做法
// const newFileNames = []
// for (const filename of fileNames) {
// if (jsfileRe.test(filename)) {
// newFileNames.push(filename)
// }
// }
// console.log(newFileNames)
// 2.filter高阶函数
// const newFileNames = fileNames.filter(filename => jsfileRe.test(filename))
// console.log(newFileNames)
有时候我们只要选择多个匹配字符的其中之一就可以:
集合(Sets)
‘o’ 中的
任意一个`;范围(Ranges)
案例:匹配手机号码
const phonePattern = /^1[356789]\d{9}$/
排除范围:除了普通的范围匹配,还有类似 [^…] 的“排除
”范围匹配;
// 手机号的规则: 1[3456789]033334444
const phoneStarts = ["132", "130", "110", "120", "133", "155"]
const phoneStartRe = /^1[3456789]\d/
const filterPhone = phoneStarts.filter(phone => phoneStartRe.test(phone))
console.log(filterPhone)
const phoneNum = "133888855555"
const phoneRe = /^1[3-9]\d{9}$/
console.log(phoneRe.test(phoneNum))
// 了解: 排除范围
// \d -> [0-9]
// \D -> [^0-9]
假设我们有一个字符串 +7(903)-123-45-67,并且想要找到它包含的所有数字。
量词
( Quantifiers )。数量 {n}
缩写:
一个或多个
,相当于 {1,}零个或一个
,相当于 {0,1}。换句话说,它使得符号变得可选;零个或多个
,相当于 {0,}。也就是说,这个字符可以多次出现或不出现;案例:匹配开始或结束标签
// 1.量词的使用
const re = /a{3,5}/ig
const message = "fdaaa2fdaaaaaasf42532fdaagjkljlaaaaf"
const results = message.match(re)
console.log(results)
// 2.常见的符号: +/?/*
// +: {1,}
// ?: {0,1}
// *: {0,}
// 3.案例: 字符串的html元素, 匹配出来里面所有的标签
const htmlElement = "哈哈哈我是标题
"
const tagRe = /<\/?[a-z][a-z0-9]*>/ig
const results2 = htmlElement.match(tagRe)
console.log(results2)
如果我们有这样一个需求:匹配下面字符串中所有使用《》包裹的内容
const message = "我最喜欢的两本书:《黄金时代》和《沉默的大多数》"
const results = message.match(/《.+》/g)
console.log(results)
默认情况下的匹配规则是查找到匹配的内容后,会继续向后查找,一直找到最后一个匹配的内容
贪婪模式
(Greedy)懒惰模式
中的量词与贪婪模式中的是相反的。
不再继续向后匹配
;?
来启用它;const message = "我最喜欢的两本书:《黄金时代》和《沉默的大多数》"
const results = message.match(/《.+?》/g)
console.log(results)
模式的一部分可以用括号括起来 (…),这称为“捕获组
(capturing group)”。
这有两个作用:
结果数组中的单独项
;方法 str.match(regexp),如果 regexp 没有 g 标志,将查找第一个匹配并将它作为一个数组返回:
案例:匹配到HTML标签,并且获取其中的内容
const str = "title
"
const result = str.match(/<(.+?)>/)
console.log(result[0])
console.log(result[1])
命名组:
const result = message.match(/(?hel)lo /i)
非捕获组:
const result = message.match(/(?hel)(lo) /)
or
是正则表达式中的一个术语,实际上是一个简单的“或”。
// 1.将捕获组作为整体
const info = "dfabcabcfabcdfdabcabcabcljcbacballnbanba;jk;j"
const abcRe = /(abc|cba|nba){2,}/ig
console.log(info.match(abcRe))
function formatDate(timestamp, formatString) {
const date = new Date(timestamp);
const obj = {
"y+": date.getFullYear(),
"M+": date.getMonth() + 1,
"d+": date.getDate(),
"h+": date.getHours(),
"m+": date.getMinutes(),
"s+": date.getSeconds(),
"S+": date.getMilliseconds()
};
for (const key in obj) {
if (new RegExp(`(${key})`).test(formatString)) {
const value = (obj[key] + "").padStart(2, "0");
formatString = formatString.replaceAll(RegExp.$1, value);
}
}
return formatString;
}
const nowDate = Date.now();
const formatStr = formatDate(nowDate, "yyyy-MM-dd hh:mm:ss.SSS");
console.log(formatStr);