Skip to content

2-17综合案例-学生统计表案例(二) ​

本页对应 第二章WebAPIs,共 6 段视频,约 44 分钟。

学习目标 ​

  • 能够根据表单输入生成包含 stuId、uname、age、salary、gender、city、time 等字段的学生对象,追加到数组后调用渲染函数更新页面,并使用表单重置方法清空输入。
  • 能够使用 localStorage.setItem 与 JSON.stringify 保存最新数组数据,使用 localStorage.getItem 与 JSON.parse 读取数据,并通过刷新页面验证新增、删除后的数据不丢失。
  • 能够使用事件委托为 tbody 注册点击事件,通过判断目标元素和自定义属性获取当前删除项索引,使用 splice 删除对应数据并重新渲染页面。
  • 能够在删除操作中加入 confirm 确认框,并根据返回值决定是否执行删除,同时将删除后的最新数组同步保存到本地存储。
  • 能够按“数组最后一条数据的 stuId + 1”生成新学号,并使用三元表达式处理空数组时默认 stuId 为 1 的情况,避免学号重复和空数组报错。
  • 能够使用正则表达式的替换方法和修饰符完成字符串替换、全局匹配或不区分大小写匹配,并验证替换结果符合预期。

知识点 ​

正则表达式是什么 ​

正则表达式(Regular Expression)是一种字符串匹配的模式(规则)。它把“什么样的字符串算合法/算目标”写成规则,再用规则去测试、替换或提取。典型场景是表单验证:比如手机号要求只能输入 11 位数字;也用于过滤敏感词、从字符串中提取特定部分。

正则表达式使用场景

正则基本使用 ​

为什么需要:如果不用规则,就只能写大量字符判断,代码长且难维护。怎么想:先把需求翻译成“规则对象”,再用 test() 看目标字符串是否匹配。怎么做:/表达式/ 是正则字面量,正则也是对象;test() 返回布尔值。易错点:test() 判断的是“是否匹配”,不是返回匹配内容;初学先区分“包含匹配”和后面的“精确匹配”。

html
<body>
  <script>
    // 正则表达式的基本使用
    const str = 'web前端开发'
    // 1. 定义规则
    const reg = /web/

    // 2. 使用正则  test()
    console.log(reg.test(str))  // true  如果符合规则匹配上则返回true
    console.log(reg.test('java开发'))  // false  如果不符合规则匹配上则返回 false
  </script>
</body>

元字符与普通字符 ​

为什么需要:普通字符只能描述它们本身,例如 /[abcdefghijklmnopqrstuvwxyz]/ 很笨重;元字符有特殊含义,能提高灵活性和匹配能力。怎么想:能用范围/简写就不要枚举。怎么做:普通字符匹配相同字符;元字符写法如 /[a-z]/ 表示英文字母范围。易错点:普通字符不是“声明范围”,[abc] 才是多选一;元字符有特殊含义,不能按普通字母理解。

边界符 ​

为什么需要:/web/ 只表示“包含 web”,web前端、前端web 都可能命中;很多验证要求“开头/结尾/整体精确”。怎么想:^ 提示开头位置,$ 提示结束位置;^ 和 $ 在一起表示精确匹配。怎么做:看下面代码逐条 test() 验证。易错点:/^web$/ 只匹配 web,不匹配 webweb;边界符管位置,不是匹配字符本身。

边界符说明

html
<body>
  <script>
    // 元字符之边界符
    // 1. 匹配开头的位置 ^
    const reg = /^web/
    console.log(reg.test('web前端'))  // true
    console.log(reg.test('前端web'))  // false
    console.log(reg.test('前端web学习'))  // false
    console.log(reg.test('we'))  // false

    // 2. 匹配结束的位置 $
    const reg1 = /web$/
    console.log(reg1.test('web前端'))  //  false
    console.log(reg1.test('前端web'))  // true
    console.log(reg1.test('前端web学习'))  // false
    console.log(reg1.test('we'))  // false  

    // 3. 精确匹配 ^ $
    const reg2 = /^web$/
    console.log(reg2.test('web前端'))  //  false
    console.log(reg2.test('前端web'))  // false
    console.log(reg2.test('前端web学习'))  // false
    console.log(reg2.test('we'))  // false 
    console.log(reg2.test('web'))  // true
    console.log(reg2.test('webweb'))  // flase 
  </script>
</body>

量词 ​

为什么需要:验证经常要求“重复几次”,例如 3 位、至少 2 位、2 到 4 位。怎么想:把量词理解为“前一个模式重复次数”。怎么做:* 表示 ≥0 次,+ 表示 ≥1 次,? 表示 0 或 1 次,{n} 固定 n 次,{n,} ≥n 次,{n,m} 在 n 到 m 次之间。易错点:逗号左右千万不要出现空格,否则匹配失败;* 允许空串,+ 不允许。

量词说明

html
<body>
  <script>
    // 元字符之量词
    // 1. * 重复次数 >= 0 次
    const reg1 = /^w*$/
    console.log(reg1.test(''))  // true
    console.log(reg1.test('w'))  // true
    console.log(reg1.test('ww'))  // true
    console.log('-----------------------')

    // 2. + 重复次数 >= 1 次
    const reg2 = /^w+$/
    console.log(reg2.test(''))  // false
    console.log(reg2.test('w'))  // true
    console.log(reg2.test('ww'))  // true
    console.log('-----------------------')

    // 3. ? 重复次数  0 || 1 
    const reg3 = /^w?$/
    console.log(reg3.test(''))  // true
    console.log(reg3.test('w'))  // true
    console.log(reg3.test('ww'))  // false
    console.log('-----------------------')

    // 4. {n} 重复 n 次
    const reg4 = /^w{3}$/
    console.log(reg4.test(''))  // false
    console.log(reg4.test('w'))  // flase
    console.log(reg4.test('ww'))  // false
    console.log(reg4.test('www'))  // true
    console.log(reg4.test('wwww'))  // false
    console.log('-----------------------')

    // 5. {n,} 重复次数 >= n 
    const reg5 = /^w{2,}$/
    console.log(reg5.test(''))  // false
    console.log(reg5.test('w'))  // false
    console.log(reg5.test('ww'))  // true
    console.log(reg5.test('www'))  // true
    console.log('-----------------------')

    // 6. {n,m}   n =< 重复次数 <= m
    const reg6 = /^w{2,4}$/
    console.log(reg6.test('w'))  // false
    console.log(reg6.test('ww'))  // true
    console.log(reg6.test('www'))  // true
    console.log(reg6.test('wwww'))  // true
    console.log(reg6.test('wwwww'))  // false

    // 7. 注意事项: 逗号两侧千万不要加空格否则会匹配失败

  </script>
</body>

范围与字符类 ​

为什么需要:表单常限定“只能是字母/数字/下划线”或“不能是某类字符”。怎么想:[] 表示字符范围,[abc] 多选一,[a-z] 连字符表示范围,[^a-z] 表示取反;字符类是一些常见模式的简写。怎么做:先写范围,再配合量词和边界符做整体验证。易错点:[^a-z] 的 ^ 在方括号内是取反,不是开头;用户名 6~16 位案例中 {6,16} 必须配合 ^...$ 才是整体长度校验。

范围说明

html
<body>
  <script>
    // 元字符之范围  []  
    // 1. [abc] 匹配包含的单个字符, 多选1
    const reg1 = /^[abc]$/
    console.log(reg1.test('a'))  // true
    console.log(reg1.test('b'))  // true
    console.log(reg1.test('c'))  // true
    console.log(reg1.test('d'))  // false
    console.log(reg1.test('ab'))  // false

    // 2. [a-z] 连字符 单个
    const reg2 = /^[a-z]$/
    console.log(reg2.test('a'))  // true
    console.log(reg2.test('p'))  // true
    console.log(reg2.test('0'))  // false
    console.log(reg2.test('A'))  // false
    // 想要包含小写字母,大写字母 ,数字
    const reg3 = /^[a-zA-Z0-9]$/
    console.log(reg3.test('B'))  // true
    console.log(reg3.test('b'))  // true
    console.log(reg3.test(9))  // true
    console.log(reg3.test(','))  // flase

    // 用户名可以输入英文字母,数字,可以加下划线,要求 6~16位
    const reg4 = /^[a-zA-Z0-9_]{6,16}$/
    console.log(reg4.test('abcd1'))  // false 
    console.log(reg4.test('abcd12'))  // true
    console.log(reg4.test('ABcd12'))  // true
    console.log(reg4.test('ABcd12_'))  // true

    // 3. [^a-z] 取反符
    const reg5 = /^[^a-z]$/
    console.log(reg5.test('a'))  // false 
    console.log(reg5.test('A'))  // true
    console.log(reg5.test(8))  // true

  </script>
</body>

字符类简写说明

字符类简写表

调试与场景补充 ​

转写稿中的综合案例反复用表单验证:用户名要求 6 到 10 位、手机号 11 位、密码 6 到 20 位、确认密码要与上面一致;输入不合法时提示“不合法”。这里要把“非空判断”写对(转写稿里的“飞空判断”是同音误写),把“索引号”写对(“缩引号”),把数组 array、JSON 字符串等术语纠正。调试正则时,最稳的方式就是像笔记代码一样,用 console.log(reg.test(...)) 先测合法值,再测边界值:空串、少一位、多一位、大小写、数字和符号。只有先确认规则本身正确,再放进表单事件里提示用户,才不会把“规则错”误判成“事件没绑定”。

本节要解决的问题 ​

这一节学习两个紧密相关的知识点:replace 替换方法和正则修饰符。笔记中的需求很明确:把字符串“欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神”里的“前端”替换成“web”。如果直接写 replace,只能替换第一个“前端”;如果加上修饰符 g,才能把所有“前端”都替换掉。

先看笔记中的示意图:

replace替换方法示意图

转写稿主体讲的是后续综合案例中的新增、删除、本地存储等内容,并没有展开 replace 的具体调试过程,因此这里不把综合案例逻辑硬套到本节。转写稿中反复出现“正则表达式”,可以确认本节处在正则表达式学习阶段;其中“耳瑞/aree”应理解为 array,“杰森”应理解为 JSON,这些属于后续案例,本节先聚焦 replace 和修饰符。

replace 的基本用法 ​

为什么需要:字符串中的内容经常需要批量或局部替换,例如把“前端”改成“web”,把敏感词替换成 ***。手动查找再拼接很麻烦,replace 可以直接返回替换后的新字符串。

怎么想:replace 的基本形式是 字符串.replace(要匹配的内容, 替换成的内容)。要匹配的内容可以是普通字符串,也可以是正则表达式;第二个参数是替换后的内容。

怎么做:先写最基础的版本:

html
<body>
  <script>
    // 替换和修饰符
    const str = '欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'
    // 1. 替换  replace  需求:把前端替换为 web
    // 1.1 replace 返回值是替换完毕的字符串
    // const strEnd = str.replace(/前端/, 'web') 只能替换一个
  </script>
</body>

这里要特别注意:replace 的返回值才是替换完毕的字符串。也就是说,不能只写 str.replace(/前端/, 'web') 就以为原字符串变了;如果想使用结果,应当接收返回值,例如 const strEnd = str.replace(/前端/, 'web')。

易错点:replace 不会修改原字符串。字符串本身是不可变的,替换结果通过返回值给出。另一个易错点是正则字面量不要写成字符串,例如不要写成 replace('/前端/', 'web'),那会按普通字符串去匹配,而不是按正则表达式匹配。

为什么只替换一个 ​

为什么需要:笔记中明确写了“只能替换一个”。这不是 replace 写错了,而是因为正则 /前端/ 没有加全局修饰符,默认只匹配第一个满足条件的位置。

怎么想:先观察原字符串,里面出现了两次“前端”。如果只用 /前端/,执行结果只会把第一处替换掉,第二处仍然是“前端”。

怎么做:可以先用注释中的写法验证:

js
const strEnd = str.replace(/前端/, 'web')
console.log(strEnd)

运行后应当看到第一个“前端”变成“web”,第二个“前端”保持不变。这个现象是理解 g 修饰符的入口。

易错点:不要误以为 replace 天生就会替换全部。默认行为是匹配一次、替换一次;要全部替换,必须让正则具备全局匹配能力。

修饰符 g:全局替换 ​

为什么需要:需求是“把前端替换为 web”,从语义上看,两处“前端”都应当被替换。只替换第一个显然不完整。

怎么想:g 是单词 global 的缩写,表示全局匹配。把 g 写在正则字面量的斜杠后面,例如 /前端/g,就能匹配所有满足正则表达式的结果。

怎么做:笔记中的完整写法是:

html
<body>
  <script>
    // 替换和修饰符
    const str = '欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'
    // 1. 替换  replace  需求:把前端替换为 web
    // 1.1 replace 返回值是替换完毕的字符串
    // const strEnd = str.replace(/前端/, 'web') 只能替换一个

    // 2. 修饰符 g 全部替换
    const strEnd = str.replace(/前端/g, 'web')
    console.log(strEnd) 
  </script>
</body>

此时 strEnd 中所有“前端”都会变成“web”。原字符串 str 仍然保持原样。

易错点:g 要写在正则字面量第二个斜杠的后面,不能写在替换内容里;也不要写成 replace('前端/g', 'web'),因为那是普通字符串,不是正则。

修饰符 i:忽略大小写 ​

为什么需要:笔记中说明 i 是单词 ignore 的缩写,正则匹配时字母不区分大小写。做英文内容替换、表单验证时,用户可能输入 Web、WEB、web,如果不忽略大小写,很容易漏匹配。

怎么想:i 控制的是“匹配时是否区分大小写”,g 控制的是“是否全局匹配”。两者解决的是不同问题:i 管大小写,g 管次数。

怎么做:如果要把字符串中的 web 不区分大小写地替换掉,可以写成 /web/i;如果既要忽略大小写又要全部替换,就组合成 /web/gi。修饰符顺序通常不影响含义,gi 和 ig 都可以。

易错点:本节笔记只给出了 i 和 g 的说明,不要额外编造其他修饰符的行为。写组合修饰符时,要写在正则字面量结尾,例如 /前端/gi,而不是 replace(/前端/, 'web', 'g')。

调试与验证思路 ​

为什么需要:替换结果是否符合预期,不能只看代码“像不像”,要打印结果验证。

怎么想:先验证“只替换一个”,再验证“全局替换”,最后再考虑大小写。这样能清楚看到修饰符带来的差异。

怎么做:可以保留两行对比:

js
const one = str.replace(/前端/, 'web')
const all = str.replace(/前端/g, 'web')
console.log(one)
console.log(all)

观察 one 和 all 的差异,就能理解 g 的作用。i 可以用英文示例单独验证,例如比较 /web/ 和 /web/i 对 Web 的匹配差异。

易错点:调试时不要把 console.log(str) 和 console.log(strEnd) 混淆;str 是原字符串,strEnd 才是替换后的返回值。

小结 ​

replace 负责替换,返回替换完毕的新字符串;默认只替换第一个匹配项。g 让正则全局匹配,从而替换所有结果;i 让正则匹配时忽略字母大小写。写代码时要牢记:replace 不改变原字符串,修饰符要写在正则字面量后面,全局替换用 /前端/g,需要忽略大小写时再用 i 组合。

课件图示 ​

课件第26页:1.3 替换和修饰符 l 修饰符约束正则执行的某些细节行为,如是否区分大小写、是

课件第5页:1.1.1 什么是正则表达式 l 正则表达式(Regular Expressio

课件第7页:总结 总结 1.正则表达式是什么? Ø 是一种字符串匹配的模式(规则) 2.正则

课件第25页:1.3 替换和修饰符 l replace 替换方法,可以完成字符的替换 l 语法

课件第6页:1.1.2 正则基本使用 l 正则基本使用分为两步: 定义规则 使用正则 l c

课件第20页:案例 用户名验证案例 需求:用户名要求用户英文字母,数字,下划线或者短横线组成,

课件第28页:可以帮我们快速生成正则表达式 any-rule 推荐一个vscode正则插件

课件第27页:案例 利用正则隐藏手机号中间四位 分析: ①:手机号前三位显示,中间四位隐藏为*

代码示例 ​

示例一:正则基本使用 + 边界符 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>正则基本使用与边界符</title>
</head>
<body>
  <script>
    // 正则表达式的基本使用
    const str = 'web前端开发'
    // 1. 定义规则
    const reg = /web/

    // 2. 使用正则  test()
    console.log(reg.test(str))         // true  如果符合规则匹配上则返回true
    console.log(reg.test('java开发'))  // false 如果不符合规则匹配上则返回 false

    // 元字符之边界符
    // 1. 匹配开头的位置 ^
    const regStart = /^web/
    console.log(regStart.test('web前端'))     // true
    console.log(regStart.test('前端web'))     // false
    console.log(regStart.test('前端web学习')) // false
    console.log(regStart.test('we'))          // false

    // 2. 匹配结束的位置 $
    const regEnd = /web$/
    console.log(regEnd.test('web前端'))     // false
    console.log(regEnd.test('前端web'))     // true
    console.log(regEnd.test('前端web学习')) // false
    console.log(regEnd.test('we'))          // false

    // 3. 精确匹配 ^ $
    const regExact = /^web$/
    console.log(regExact.test('web前端'))     // false
    console.log(regExact.test('前端web'))     // false
    console.log(regExact.test('前端web学习')) // false
    console.log(regExact.test('we'))          // false
    console.log(regExact.test('web'))         // true
    console.log(regExact.test('webweb'))      // false
  </script>
</body>
</html>

关键行与易错点

  • const reg = /web/:/ / 之间是正则表达式字面量,正则表达式本身也是对象,不是字符串。
  • reg.test(str):test() 用来查看正则与指定字符串是否匹配,返回 true / false。
  • ^ 只表示开头位置,$ 只表示结尾位置;/^web/ 匹配 'web前端',但匹配不了 '前端web'。
  • ^ 和 $ 同时出现表示精确匹配:/^web$/ 只有 'web' 为 true,'webweb' 为 false。
  • 易错点:笔记中各片段是分开的独立示例,合并到一个 <script> 时不能再重复 const reg,否则 Identifier 'reg' has already been declared 报错,所以这里改名为 regStart、regEnd、regExact。

示例二:元字符——量词与范围 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>元字符:量词与范围</title>
</head>
<body>
  <script>
    // ===== 元字符之量词 =====
    // 1. * 重复次数 >= 0 次
    const regStar = /^w*$/
    console.log(regStar.test(''))   // true
    console.log(regStar.test('w'))  // true
    console.log(regStar.test('ww')) // true

    // 2. + 重复次数 >= 1 次
    const regPlus = /^w+$/
    console.log(regPlus.test(''))   // false
    console.log(regPlus.test('w'))  // true
    console.log(regPlus.test('ww')) // true

    // 3. ? 重复次数 0 || 1
    const regQ = /^w?$/
    console.log(regQ.test(''))   // true
    console.log(regQ.test('w'))  // true
    console.log(regQ.test('ww')) // false

    // 4. {n} 重复 n 次
    const reg3 = /^w{3}$/
    console.log(reg3.test(''))    // false
    console.log(reg3.test('w'))   // false
    console.log(reg3.test('ww'))  // false
    console.log(reg3.test('www')) // true
    console.log(reg3.test('wwww'))// false

    // 5. {n,} 重复次数 >= n
    const reg5 = /^w{2,}$/
    console.log(reg5.test(''))   // false
    console.log(reg5.test('w'))  // false
    console.log(reg5.test('ww')) // true
    console.log(reg5.test('www'))// true

    // 6. {n,m}   n =< 重复次数 <= m
    const reg6 = /^w{2,4}$/
    console.log(reg6.test('w'))     // false
    console.log(reg6.test('ww'))    // true
    console.log(reg6.test('www'))   // true
    console.log(reg6.test('wwww'))  // true
    console.log(reg6.test('wwwww')) // false

    // 7. 注意事项:逗号两侧千万不要加空格否则会匹配失败

    // ===== 元字符之范围 [] =====
    // 1. [abc] 匹配包含的单个字符,多选1
    const regOne = /^[abc]$/
    console.log(regOne.test('a'))  // true
    console.log(regOne.test('b'))  // true
    console.log(regOne.test('c'))  // true
    console.log(regOne.test('d'))  // false
    console.log(regOne.test('ab')) // false

    // 2. [a-z] 连字符 单个
    const regRange = /^[a-z]$/
    console.log(regRange.test('a')) // true
    console.log(regRange.test('p')) // true
    console.log(regRange.test('0')) // false
    console.log(regRange.test('A')) // false

    // 想要包含小写字母,大写字母,数字
    const regMix = /^[a-zA-Z0-9]$/
    console.log(regMix.test('B')) // true
    console.log(regMix.test('b')) // true
    console.log(regMix.test(9))   // true
    console.log(regMix.test(',')) // false

    // 用户名可以输入英文字母,数字,可以加下划线,要求 6~16 位
    const regUser = /^[a-zA-Z0-9_]{6,16}$/
    console.log(regUser.test('abcd1'))   // false
    console.log(regUser.test('abcd12'))  // true
    console.log(regUser.test('ABcd12'))  // true
    console.log(regUser.test('ABcd12_')) // true

    // 3. [^a-z] 取反符
    const regNeg = /^[^a-z]$/
    console.log(regNeg.test('a')) // false
    console.log(regNeg.test('A')) // true
    console.log(regNeg.test(8))   // true
  </script>
</body>
</html>

关键行与易错点

  • 量词控制某个模式的重复次数:* 是 >= 0 次,+ 是 >= 1 次,? 是 0 或 1 次,{n} 恰好 n 次,{n,} 至少 n 次,{n,m} 是 n 到 m 次。
  • 易错点:{n,m} 中逗号两侧千万不要出现空格,否则匹配失败;/^w*$/ 对空字符串也返回 true,/^w+$/ 对空字符串返回 false,两者的区别就在最小值。
  • [] 表示范围,只匹配一个字符:/^[abc]$/ 中 'ab' 是 false;[a-z] 只包含小写,'A' 和 '0' 都是 false。
  • 组合写法 /^[a-zA-Z0-9_]{6,16}$/:范围负责"能出现哪些字符",量词负责"出现几位",^ $ 负责整体精确匹配。
  • [^a-z] 中 ^ 放在方括号里面表示取反(不是取反,而是"除了 a-z 以外的字符"),放在外面才是匹配开头。
  • regMix.test(9) 返回 true:test() 参数会被当作字符串处理,数字 9 变成 '9' 参与匹配。

示例三:replace 替换与修饰符 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>替换和修饰符</title>
</head>
<body>
  <script>
    // 替换和修饰符
    const str = '欢迎大家学习前端,相信大家一定能学好前端,都成为前端大神'

    // 1. 替换  replace  需求:把前端替换为 web
    // 1.1 replace 返回值是替换完毕的字符串
    const strOne = str.replace(/前端/, 'web')   // 只能替换一个
    console.log(strOne)

    // 2. 修饰符 g 全部替换
    const strEnd = str.replace(/前端/g, 'web')
    console.log(strEnd)
  </script>
</body>
</html>

关键行与易错点

  • replace() 的返回值是替换完毕的新字符串,原字符串 str 不变;不接收返回值就等于没替换。
  • 不带修饰符时 str.replace(/前端/, 'web') 只替换第一个匹配结果。
  • g 是单词 global 的缩写,匹配所有满足正则表达式的结果,/前端/g 才能把两处"前端"全部替换为 web。
  • i 是单词 ignore 的缩写,正则匹配时字母不区分大小写(笔记中的修饰符说明),可与 g 一起使用。
  • 易错点:replace 的第一个参数写成字符串 '前端' 也能替换,但那样无法配合修饰符做全局/忽略大小写匹配,本节统一用正则字面量写法。

常见错误 ​

  1. 现象:/^web$/.test('web前端') 返回 false,误以为正则写错。
    原因:^ 和 $ 表示精确匹配,不是“包含”。
    修法:只判断包含时去掉 ^ $;表单整串校验时保留 ^ $。

  2. 现象:/^w{2, 4}$/ 匹配 'ww' 失败。
    原因:量词 {n,m} 的逗号两侧写了空格,空格被当成匹配字符。
    修法:写成 /^w{2,4}$/,量词内部不要加空格。

  3. 现象:想校验“整串不能是小写字母”,写成 /^[^a-z]$/,结果 'AB12' 不通过。
    原因:[^...] 只对单个字符取反,不是对整串取反。
    修法:整串校验配合量词,如 /^[^a-z]+$/;需要固定长度时用 {n,m}。

  4. 现象:str.replace(/前端/, 'web') 只替换了第一处“前端”。
    原因:没有加全局修饰符 g。
    修法:写成 str.replace(/前端/g, 'web');需要忽略大小写再加 i。

  5. 现象:删除一条数据后页面正常,刷新后删除的数据又回来了。
    原因:只执行了 splice 和 render,没有把最新数组回写 localStorage。
    修法:删除后按“改数组 → JSON.stringify 持久化 → 重新渲染”执行。

  6. 现象:新增数据时 stuId 重复;全部删除后再新增直接报错。
    原因:用 arr.length + 1 生成编号,或空数组时仍读取最后一条数据的 stuId。
    修法:用 arr.length ? arr[arr.length - 1].stuId + 1 : 1。

  7. 现象:点击删除按钮拿不到当前行索引,或点到行内其他元素也触发删除。
    原因:渲染时没写 data-id,或事件委托中没判断点击目标是否为 A。
    修法:map 的 index 写入 data-id;点击后判断 e.target.tagName === 'A',再取 e.target.dataset.id。

  8. 现象:点“添加”后表单没有变成预期的空值。
    原因:form.reset() 是恢复表单默认值,不是强制清空;默认 value 有值时会被恢复。
    修法:需要空值时手动清空对应字段,或确保表单默认值本身为空。

练习 ​

  1. 写一个精确匹配的正则:用户名只能是英文字母、数字、下划线,长度 6~16 位;并说明 test('') 的结果。
  2. 判断下列字符串哪些能通过 /^w{2,4}$/:''、'w'、'ww'、'www'、'wwww'、'wwwww'、'ww,ww'。
  3. 将字符串 '欢迎大家学习前端,前端很重要' 中所有“前端”替换为 web,写出 replace 调用。
  4. 补全删除业务顺序:事件委托绑定 tbody 点击 → 判断点击 A → 取 data-id → confirm → splice → 持久化 → 重新渲染。写出关键代码结构。
  5. 新增数据后要求刷新不丢失:写出“生成对象 → 追加数组 → 持久化 → 渲染 → 重置表单”的关键调用顺序。

原视频对照 ​

#视频时长
1综合案例-新增业务生成数据和渲染页面11:36
2综合案例-新增业务实现本地存储05:17
3综合案例-删除业务上07:44
4综合案例-删除业务下05:53
5综合案例-关于stuId的处理10:44
6今日内容03:31

小结 ​

  1. 表单整串校验优先使用 ^...$;只做包含/查找时不要乱加边界符。
  2. 量词和范围写法中,空格会参与匹配,{2,4} 不能写成 {2, 4}。
  3. [^...] 只对单个字符取反,整串校验必须配合量词。
  4. 动态渲染的删除按钮优先用事件委托,索引通过 data-id 传递。
  5. 新增、删除后都要按“修改数组 → 持久化 → 重渲染”的顺序收尾。
  6. 本地存储存数组必须 JSON.stringify,读取后再 JSON.parse。
  7. stuId 生成要基于最后一条数据的 stuId + 1,空数组回退为 1。
  8. form.reset() 是恢复默认值,不保证字段一定为空。