前言

  1. 关于正则表达式
    基于同学们的强烈呼吁、回顾我们前面的第1季章节15搜索:addClass()和我们本季课程搜索:获取留言板输入的内容多次用到正则表达式、考虑到接下来的项目会更多用到正则表达式,我们本章节来学习一下正则表达式的相关知识。

  2. 正则表达式介绍 [正则表达式介绍] [正则表达式RegExp对象]
    正则表达式(regular expression)是一个描述字符模式的对象。JS中的 RegExp 类表示正则表达式,而 String 和 RegExp 都定义了使用正则表达式进行强大的模式匹配和文本检索与替换的函数(关于String的匹配检索替换我们已经在第1季-12章节基本包装类型-String类型讲过了),但是当这个字符串变得很复杂,需要匹配的功能变得很强大的时候,我们的String字符串对象方法就变得有心无力了,这个时候就需要用我们的正则表达式来做匹配了。

    正则表达式主要用来验证客户端的输入数据。用户填写完表单单击按钮之后,表单就会被发送到服务器,在服务器端通常会用 PHP、ASP.NET、Node.js、Java等服务器脚本对其进行进一步处理。因为客户端验证,可以节约大量的服务器端的系统资源,并且提供更好的用户体验。

    关于正则表达式的用途现在大家都清楚了:帮我们验证数据的合法性、帮我们匹配数据等功能,大家在前面的课程已经初步体验过了,接下来我们先来创建正则表达式。

# 一、创建正则表达式

创建正则表达式和创建字符串类似,创建正则表达式提供了两种方法,一种是采用 new运算符另一个是采用字面量方式关于什么是new运算符、什么是字面量,这个我们在第1季js基础课程已经都讲过了,现在大家应该是轻松拿捏了)。

# ① new运算符创建正则表达式

let girl = new RegExp('DiLiReBa');//第一个参数是模式字符串
console.log(girl);//返回: /DiLiReBa/
//两个反斜杠 /DiLiReBa/ 就是正则表达式的字面量表示法,不过我们上面声明的时候用的new运算符
//第二个参数可选模式修饰符,可选项
let girl = new RegExp('DiLiReBa','ig');//第二个参数是可选项,可有可没有
console.log(girl);//返回:/DiLiReBa/gi

模式修饰符的可选参数

参数

含义
i 忽略大小写 (就是匹配的时候不管你的字母是大写还是小写都是一个意思)
g 全局匹配 (一个字符串里面有多少个字符:如 i,能找到i的字母都给它找出来)
m 多行匹配 (字符串有多行的时候,如果不加m只会匹配第一行,加上m就可以匹配到所有行)

# ② 字面量方式创建正则表达式

let girl = /DiLiReBa/;     //字面量正则
console.log(girl);//返回: /DiLiReBa/
let _girl = /DiLiReBa/ig;  //字面量正则,带修饰符
console.log(_girl);//返回:/DiLiReBa/gi 

# 二、测试正则表达式

RegExp 对象包含两个方法:test()和 exec(),功能基本相似,用于测试字符串匹配。test()方法在字符串中查找是否存在指定的正则表达式并返回布尔值,如果存在则返回 true,不存在则返回 false。exec()方法也用于在字符串中查找指定正则表达式,如果 exec()方法执行成功,则返回包含该查找字符串的相关信息数组。如果执行失败,则返回 null。

# ① test方法:在字符串中测试模式匹配,返回 true 或 false

let patter = new RegExp('DiLiReBa'); //模式
let str = 'dilireba';   //要匹配的字符串
//用法:模式.test(要匹配的字符串)
let res = patter.test(str); //test方法,返回布尔值
console.log(res); // 返回 false
//为什么是false, 因为模式和匹配的字符串不相等,因为字母大小写不一致

忽略大小写

let patter = new RegExp('DiLiReBa','i'); //模式,模式修饰符
let str = 'dilireba';   //要匹配的字符串
//用法:模式.test(要匹配的字符串)
let res = patter.test(str); //test方法,返回布尔值
console.log(res); // 返回 true
//为什么是true, 因为模式修饰符忽略了大小写,所以可以匹配到

字面量写法

let patter = /DiLiReBa/i;
let str = 'dilireba';
let res = patter.test(str);
console.log(res); // true

使用一句话匹配

let res = /DiLiReBa/i.test('dilireba');
console.log(res);//true

查找字符串中是否有匹配的字符

let patter = /dilireba/i;
let str = '迪丽热巴的拼音是:DiLiReBa,她的全名叫:迪丽热巴迪力木拉提';
console.log(patter.test(str));

# ② exec方法:在字符串中执行匹配搜索,返回结果数组,执行失败,则返回 null

let patter = /dilireba/i;
let str = '迪丽热巴的拼音是:DiLiReBa,她的全名叫:迪丽热巴迪力木拉提';
let res = patter.exec(str);
alert(res); // DiLiReBa
console.log(typeof res);//object
console.log(Array.isArray(res));//true 
//返回的是数组,有就返回数组的值,没有匹配到则返回null
let patter1 = /love/i;
alert(patter1.exec(str));//null

exec 方法还有其他具体应用,我们在学完后面一些内容之后再举例

# 三、字符串的正则表达式方法

我们上面讲的test方法、exec方法是正则表达式的测试方法,是正则表达式本身就具有的方法,接下来我们要讲的方法,是字符串String对象提供的4个方法,但是这四个方法可以用在正则表达式里面的。
回顾一下我们第二学期第1季-章节12.javascript基本包装类型-3、String类型-7.String类型字符串模式匹配方法搜索:String类型,其中有:match(pattern)、replace(pattern, replacement)、search(pattern)、split(pattern)这4个方法就可以用在正则表达式的模式匹配上,接下里我们再详细讲一下这4个方法。

# ① match方法:就是一个查找的功能,获取匹配的字符串,返回数组或 null

let patter = /dilireba/ig;//忽略大小写,全局匹配
let str = '迪丽热巴的拼音是:DiLiReBa,小写是:dilireba,她的全名叫:迪丽热巴迪力木拉提';
//接下来是用的字符串的方法,所以注意用法:字符串.方法
let res = str.match(patter);
console.log(res);// ['DiLiReBa', 'dilireba']
//注意:
//1. 如果不开启全局,则匹配第一个字符串返回数组 ['DiLiReBa']
console.log(res[0]);

# ② search方法:根据匹配的字符串,返回位置索引(从0开始)

let patter = /dilireba/ig;//忽略大小写,全局匹配
let str = '迪丽热巴的拼音是:DiLiReBa,小写是:dilireba,她的全名叫:迪丽热巴迪力木拉提';
//接下来是用的字符串的方法,所以注意用法:字符串.方法
let res = str.search(patter);
console.log(res);//返回:9 也就是第10个字符
//1、返回的第一个匹配的位置,找到后就返回了,不会往后面找
//2、因此匹配的时候,可以不用加 g
//3、找不到则返回 -1

# ③ split方法:按照匹配模式,拆分成字符串数组

let patter = /dilireba/ig;//忽略大小写,全局匹配
let str = '迪丽热巴的拼音是:DiLiReBa,小写是:dilireba,她的全名叫:迪丽热巴迪力木拉提';
//接下来是用的字符串的方法,所以注意用法:字符串.方法
let res = str.split(patter);
console.log(res);//返回:['迪丽热巴的拼音是:', ',小写是:', ',她的全名叫:迪丽热巴迪力木拉提']

# ④ replace方法: 替换匹配到的数据

let patter = /dilireba/ig;//忽略大小写,全局匹配
let str = '迪丽热巴的拼音是:DiLiReBa,小写是:dilireba,她的全名叫:迪丽热巴迪力木拉提';
//接下来是用的字符串的方法,所以注意用法:字符串.方法
let res = str.replace(patter,'love');//返回替换后的字符串
console.log(res);//'迪丽热巴的拼音是:love,小写是:love,她的全名叫:迪丽热巴迪力木拉提'
//注意:
//1.要开启全局,才能全部匹配到,没有开启全局,则匹配第一个就返回了

# 小案例:模拟百度搜索,搜索的关键字设置成红色

$(function () {
  let str = `<div style="width:400px;margin:50px auto;">
  <p>美女的标准是什么:</p>
  <p>性感的身材属于美女的第一个标准</p>
  <p>大眼睛那是美女必须要具备的</p>
  <p>五官端正、高鼻梁、性感的大嘴唇才能叫美女</p>
  <div>`;
  $('body').append(str);
});
$(function () {

  let str = `<div style="width:400px;margin:50px auto;">
  <p>美女的标准是什么:</p>
  <p>性感的身材属于美女的第一个标准</p>
  <p>大眼睛那是美女必须要具备的</p>
  <p>五官端正、高鼻梁、性感的大嘴唇才能叫美女</p>
  <div>`;
  $('body').append(str);

  //把str中的“美女”文字变成红色
  let keyword = '美女';
  let patter = new RegExp(keyword, 'g');
  str = str.replace(patter, `<span style="color: red;">${keyword}</span>`);
  $('body').append(str);

  //把str中的“美女”“大”文字变成蓝色
  let arr = ['美女', '大'];
  for (const key of arr) {
    //  console.log(key);
    let patter = new RegExp(key, 'g');
    str = str.replace(patter, `<span style="color: blue;">${key}</span>`);

    if(key == '大'){
      str = str.replace(patter, `<span style="color: blue;font-size:30px">${key}</span>`);
    }else if(key == '美女'){
      str = str.replace(patter, `<span style="color: red;">${key}</span>`);
    }
  }
  $('body').append(str);
});

# 四、正则表达式RegExp对象的静态属性、实例属性(了解)

静态属性就是直接通过RegExp调用,无需声明无需new,实例属性就是需要先创建正则表达式new一个正则实例,在进行调用(学完我们前面的面向对象与原型,这个概念现在很容易理解

# 1、 静态属性

属 性

短 名

含 义
input $_ 当前被匹配的字符串
leftContext $` 最后一次匹配前的子串
rightContext $' 在上次匹配之后的子串
lastMatch $& 最后一个匹配字符串
lastParen $+ 最后一对圆括号内的匹配子串
console.log(RegExp.input);

let patter = /dilireba/ig;
let str = '迪丽热巴的拼音是:DiLiReBa,小写是:dilireba,她的全名叫:迪丽热巴迪力木拉提';
let res = str.match(patter);
console.log(res);
//执行一下即可

# ① 属性:input,短名:$_ , 当前被匹配的字符串

console.log(RegExp.input);
console.log(RegExp['$_']);
//'迪丽热巴的拼音是:DiLiReBa,小写是:dilireba,她的全名叫:迪丽热巴迪力木拉提'

# ② 属性:leftContext,短名:$` , 最后一次匹配前的子串

console.log(RegExp.leftContext);
console.log(RegExp['$`']);
//'迪丽热巴的拼音是:DiLiReBa,小写是:'

# ③ 属性:rightContext,短名:$' , 在上次匹配之后的子串

console.log(RegExp.rightContext);
console.log(RegExp['$\'']);
// ',她的全名叫:迪丽热巴迪力木拉提'

# ④ 属性:lastMatch,短名:$& , 最后一个匹配字符串

console.log(RegExp.lastMatch);//'dilireba'
console.log(RegExp['$&']);//'dilireba'

# ⑤ 属性:lastParen,短名:$+ , 最后一对圆括号内的匹配子串

let patter = /(d)ilireba/ig;
console.log(RegExp.lastParen);//d
console.log(RegExp['$+']);//d

# 2、 实例属性

属 性

含 义
global Boolean 值,表示 g 是否已设置
ignoreCase Boolean 值,表示 i 是否已设置
lastIndex 整数,代表下次匹配将从哪里字符位置开始
multiline Boolean 值,表示 m 是否已设置
Source 正则表达式的源字符串形式
//所谓实例属性,就是需要new实例化一个正则
// let patter = new RegExp('dilireba','ig');
let patter = /dilireba/ig;
//是否全局了 g
console.log(patter.global); //true

//是否忽略大小写 i
console.log(patter.ignoreCase); //true

//是否支持多行匹配 m
console.log(patter.multiline); //false

//下次的匹配位置
let str = 'dilireba dilireba dilireba';
patter.test(str);
console.log(patter.lastIndex); //8
patter.lastIndex = 15;//还可以手动设置
console.log(patter.lastIndex); 

//正则表达式的源字符串
console.log(patter.source); //'dilireba'

# 五、正则表达式元字符(包含特殊含义的字符)

# 一、 单个字符和数字、重复字符

单个字符和数字

元字符/元符号

匹配情况
. 匹配除换行符外的任意字符
[a-z0-9] 匹配括号中的字符集中的任意字符
[^a-z0-9] 匹配任意不在括号中的字符集中的字符
\d 匹配数字
\D 匹配非数字,同[^0-9]相同
\w 匹配字母和数字及 _
\W 匹配非字母和数字及 _

重复字符

元字符/元符号

匹配情况
x? 匹配 0 个或 1 个 x
x* 匹配 0 个或任意多个 x
x+ 匹配至少一个 x
(xyz)+ 匹配至少一个(xyz)
x{m,n} 匹配最少 m 个、最多 n 个 x

# 1、 点符号匹配除了换行符(\n)外的任意字符

//点符号匹配除了换行符(\n)外的任意字符
let patter = /dilireba/;
console.log(patter.test('dilireba'));//true

// di1ireba  diaireba  di@ireba  di迪ireba
//点符号匹配
let patter1 = /di.ireba/;
console.log(patter1.test('di1ireba'));//true
console.log(patter1.test('diaireba'));//true
console.log(patter1.test('di@ireba'));//true
console.log(patter1.test('di迪ireba'));//true
//当然,除换行符(\n)之外  di\nireba
console.log(patter.test('di\nireba'));//false


//一个点匹配一个任意字符,多个点匹配多个任意字符
// di?ire!a  di丽ire巴a
let patter2 = /di.ire.a/;
console.log(patter2.test('di?ire!a'));//true
console.log(patter2.test('di丽ire巴a'));//true

注意: 只需要保证点的位置一一对应,有几个点就可以匹配几个任意字符,换行符(\n)除外

有的同学觉得,太麻烦了,要点和匹配的位置一一对应,如果我要匹配100个位置,岂不是要写一百个点,有没有方便的写法?

# 2、 点符号和重复字符配合使用

在讲它们配合使用之前,我们先学习一下重复字符的使用

# ① 重复字符:x?,表示:匹配 0 个或 1 个 x (x可以换成任意字符)

//重复字符:x?,表示:匹配 0 个或 1 个 x (x可以换成任意字符)
//ggle  gogle 
let patter = /go?gle/;//o? 表示0个,1个o
console.log(patter.test('ggle')); //true
console.log(patter.test('gogle')); //true
console.log(patter.test('google')); //false

# ② 重复字符:x*,表示:匹配 0 个或 1 个 或者任意多个 x (x可以换成任意字符)

//重复字符:x*,表示:匹配 0 个或 1 个 或者任意多个 x (x可以换成任意字符)
//ggle  gogle  google  gooooogle
let patter = /go*gle/;//o* 表示0个,1个,或者多个o
console.log(patter.test('ggle')); //true
console.log(patter.test('gogle')); //true
console.log(patter.test('google')); //true
console.log(patter.test('gooooogle')); //true

# ③ 重复字符:x+,表示:匹配 至少1个 或者任意多个 x (x可以换成任意字符)

//重复字符:x+,表示:匹配至少1 个 或者任意多个 x (x可以换成任意字符)
//gogle  google  gooooogle
let patter = /go+gle/;//o+ 表示至少1个,或者多个o
console.log(patter.test('ggle')); //false
console.log(patter.test('gogle')); //true
console.log(patter.test('google')); //true
console.log(patter.test('gooooogle')); //true

# ④ 重复字符:x{m,n},表示:匹配最少 m 个、最多 n 个 x, x{m}表示:只能有m个x, x{m,}表示:有m个x或者以上个x (x可以换成任意字符)

//重复字符:x{m,n},表示:匹配最少 m 个、最多 n 个 x(x可以换成任意字符)
//ggle  gogle  google  gooooogle   o{0,5}  表示:匹配最少 0 个、最多 5 个 o
//gogle  google  gooooogle   o{1,5}
let patter = /go{1,5}gle/;// o{1,5}  表示:匹配最少 1 个、最多 5 个 o
console.log(patter.test('gogle')); //true
console.log(patter.test('google')); //true
console.log(patter.test('gooooogle')); //true
console.log(patter.test('gooogle')); //true
console.log(patter.test('goooogle')); //true
//x{m} 只能有m个x (x可以换成任意字符)
// gooogle   o{3} 只能匹配3个o
let patter = /go{3}gle/;
console.log(patter.test('gooogle')); //true
//x{m,} 有m个x或者以上个x (x可以换成任意字符)
// gooogle  goooogle goooooooogle  o{3,} 有3个o或者以上个o 
let patter = /go{3,}gle/;
console.log(patter.test('gooogle')); //true
console.log(patter.test('goooogle')); //true
console.log(patter.test('goooooooogle')); //true

# ⑤ 重复字符:(xyz)+,表示:匹配至少一个(xyz),括号可以看成分组,分组里面的元素可以是任意多个字符

//重复字符:(xyz)+,表示:匹配至少一个(xyz),括号可以看成分组,分组里面的元素可以是任意多个字符
// 'She loves me, I love you'  匹配:love   /(love)+/
// '我最喜欢的人是你, 你最喜欢的人却是他,他最喜欢的却是狗'  匹配:最喜欢的  /(最喜欢的)+/

let patter = /(love)+/; //  /(love)+/表示: 匹配至少一个love
console.log(patter.test('She loves me, I love you')); // true

let patter1 = /(最喜欢的)+/;
console.log(patter1.test('我最喜欢的人是你, 你最喜欢的人却是他,他最喜欢的却是狗')); // true

# ⑥ 任意一个匹配:[a-z]匹配26个小写字母任意一个,[A-Z]匹配26个大写字母任意一个,[0-9]匹配0到9的数字任意一个,[a-zA-Z0-9]匹配混合字母和数字中的任意一个

//任意一个匹配:[a-z]匹配26个小写字母任意一个,[A-Z]匹配26个大写字母任意一个,
// [0-9]匹配0到9的数字任意一个,[a-zA-Z0-9]匹配混合字母和数字中的任意一个
// Ilove  2love  ylove  
let patter = /[a-zA-Z0-9]love/;//不要修饰符igm的情况下
console.log(patter.test('Ilove')); //true
console.log(patter.test('2love')); //true
console.log(patter.test('ylove')); //true

// I520ylove  5iulove  结合重复字符使用
let patter = /[a-zA-Z0-9]*love/; // let patter = /[a-z0-9]*love/i;
console.log(patter.test('I520ylove'));//true
console.log(patter.test('5iulove'));//true

# ⑦ 任意一个不匹配:[^a-z]不匹配26个小写字母,[^A-Z]不匹配26个大写字母,[^0-9]不匹配0到9的数字,[^a-zA-Z0-9]不匹配混合字母和数字

//任意一个不匹配:[^a-z]不匹配26个小写字母,[^A-Z]不匹配26个大写字母,
//[^0-9]不匹配0到9的数字,[^a-zA-Z0-9]不匹配混合字母和数字
let patter = /[0-9]oogle/;
console.log(patter.test('7oogle'));//true
let patter1 = /[^0-9]oogle/;
console.log(patter1.test('7oogle'));//false

//我oogle _oogle  @oogle !oogle
let patter2 = /[^0-9a-zA-Z]oogle/;
console.log(patter2.test('我oogle'));//true
console.log(patter2.test('_oogle'));//true
console.log(patter2.test('@oogle'));//true
console.log(patter2.test('!oogle'));//true

接下来为了和锚字符做一个区分,我们先讲一下锚字符

# 3、字符类:锚字符

元字符/元符号

匹配情况
^ 行首匹配
$ 行尾匹配
\A 只有匹配字符串开始处
\b 匹配单词边界,词在[]内时无效
\B 匹配非单词边界
\G 匹配当前搜索的开始位置
\Z 匹配字符串结束处或行尾
\z 只匹配字符串结束处

# ① 锚字符:^ , 表示:从行首开始匹配

let patter = /[a-z]oogle/;
console.log(patter.test('google'));//true
console.log(patter.test('123google456'));//true 
//这个时候必须从头开始匹配
let patter1 = /^[a-z]oogle/;
//这个 ^符号,是放在第一个/后面,表示从头匹配,而不是加在[]里面的
console.log(patter1.test('google'));//true
console.log(patter1.test('123google456'));//false

# ② 锚字符:$ , 表示:从行尾开始匹配

let patter2 = /^[a-z]oogle/;
console.log(patter2.test('google'));//true
console.log(patter2.test('google456'));//true
//这个时候还要保证,行尾也要对上
let patter3 = /^[a-z]oogle$/;
console.log(patter3.test('google'));//true
console.log(patter3.test('google456'));//false
console.log(patter3.test('aoogle'));//true

# 4、字符:\d , 匹配数字,和字符集合 [0-9]相同,字符:\D , 匹配非数字,同[^0-9]相同

let patter = /[0-9]oogle/;
console.log(patter.test('1oogle'));//true
let patter1 = /\doogle/;
console.log(patter1.test('1oogle'));//true
//匹配任意8个数字: 75485858   54875123  65986965
let patter2 = /[0-9]{8}/; 
console.log(patter2.test('75485858'));//true
//可用\d表示
let patter3 = /\d{8}/; 
console.log(patter3.test('75485858'));//true
console.log(patter3.test('54875123'));//true
console.log(patter3.test('65986965'));//true
//字符:\D , 匹配非数字,同[^0-9]相同
// let patter = /[^0-9]oogle/;
let patter = /\Doogle/;
console.log(patter.test('它oogle'));//true
console.log(patter.test('google'));//true
console.log(patter.test('_oogle'));//true
console.log(patter.test('!oogle'));//true

# 5、字符:\w , 匹配字母和数字及_,和字符集合 [a-zA-Z0-9_]相同,字符:\W , 匹配非字母和数字及_,同[^a-zA-Z0-9_]相同

// let patter = /[a-zA-Z0-9_]oogle/;
let patter = /\woogle/;
console.log(patter.test('aoogle'));
console.log(patter.test('Google'));
console.log(patter.test('3oogle'));
console.log(patter.test('_oogle'));

//字符:\W , 匹配非字母和数字及_,同[^a-zA-Z0-9_]相同,和上面刚好相反

# 二、空白字符

元字符/元符号

匹配情况
\S 匹配非空白字符
\s 匹配空白字符、空格、制表符和换行符
\t 匹配制表符
\r 匹配回车字符
\n 匹配换行符
\f 匹配进纸字符
\b 表示到达边界
\0 匹配 null 字符

# ① 字符:\s,表示:匹配空白字符、空格、制表符和换行符

//字符:\s,表示:匹配空白字符、空格、制表符和换行符
//直接使用空格匹配
let patter = /goo gle/;
console.log(patter.test('goo gle'));//true
//使用 \s匹配空白字符、空格、制表符和换行符
let patter1 = /goo\sgle/;
console.log(patter1.test('goo gle'));//true

# ② 字符:\b,表示:到达边界

let patter = /google/;
console.log(patter.test('google123456'));//true
let patter1 = /google\b/;
console.log(patter1.test('google123456'));//false
console.log(patter1.test('google'));//true

# 三、选择字符(|)选择模式,匹配如:jpg|png|gif,非相等包含的意思

// 字符: | ,表示选择模式,竖线里面的任意一个都行
let patter = /jpg|png|gif/;
console.log(patter.test('jpg'));//true
console.log(patter.test('图片格式是 .png'));//true
console.log(patter.test('图片中的动画格式叫做:gif'));//true

# 四、分组模式:()做分组,\1或$1匹配第一个分组中的内容,\2或$2匹配第二个分组中的内容,依次类推

# ① 分组模式:()做分组

//分组模式:()做分组
//先回忆区间匹配
let patter = /google{3,5}$/;//区间,e出现最少3次最多5
console.log(patter.test('google'));//false
console.log(patter.test('googleee'));//true
console.log(patter.test('googleeeee'));//true
console.log(patter.test('googleeeeee'));//false

//加上括号()就变成分组了,分组可以看成一个字符
let patter1 = /(google){3,5}$/;//把google看成一个字符,匹配最少3次最多5次
console.log(patter1.test('google'));//false
console.log(patter1.test('googlegooglegoogle'));//true

# ② $1可以获取到第一个分组内容

//\1或$1匹配第一个分组中的内容,\2或$2匹配第二个分组中的内容,依次类推
let patter = /I.*You/;//.*匹配任意字符0次1次或者多次
console.log(patter.test('IloveYou'));//true
console.log(patter.test('I520You'));//true
console.log(patter.test('他喜欢她,I爱You,你爱他'));//true

//$1可以获取到第一个分组内容
let patter1 = /I(.*)You/;
console.log(RegExp.$1);//空的,需要先运行一下
// patter1.test('IloveYou');//运行方式很多
patter1.exec('IloveYou');
console.log(RegExp.$1);//love
patter1.test('他喜欢她,I爱You,你爱他');
console.log(RegExp.$1);//爱

# ③ 小案例:$1获取到第一个分组内容,并做替换

let patter1 = /I(.*)You/;
let str = '他喜欢她,I爱的是You,你爱他';
let str2 ='他喜欢她,I喜欢的是You,你爱他'
let str3 ='他喜欢她,IloveYou,你爱他'
//把自定义的内容:“爱的是”“喜欢的是”"love"加粗
document.write(str.replace(patter1,'I<b>爱的是</b>You'));
document.write(str2.replace(patter1,'I<b>$1</b>You'));
document.write(str3.replace(patter1,'I<b>$1</b>You'));

# ④ 小案例:获取多个分组内容,进行替换

//$1可以获取到第一个分组内容,$2获取第二个分组内容,依次类推
let str = '我爱你 你爱我';
//换成 '你爱我 我爱你'
let patter = /(.*)\s(.*)/;
console.log(str.replace(patter,'$2 $1'));//'你爱我 我爱你'

# 六、正则表达式:贪婪和惰性

粗俗的理解:贪婪 就是什么都是我的,惰性就是节制一点

贪 婪

惰 性

+ +?
? ??
* *?
{n} {n}?
{n,} {n,}?
{n,m} {n,m}?

这里其实是对重复字符的深层次理解

//正常根据模型替换一个字符
let str = 'abcdefghijk';
let patter = /[a-z]/;
console.log(str.replace(patter,'我'));//'我bcdefghijk'
//贪婪模式
let patter1 = /[a-z]+/;//贪婪模式 将所有字符串变成了 '我'一个字符
console.log(str.replace(patter1,'我'));//'我'
//看一下惰性模式
let patter2 = /[a-z]+?/;//匹配符合条件的第一个字符,后面没有匹配
console.log(str.replace(patter2,'我'));//'我bcdefghijk'
//开启全局,并使用惰性模式
let patter3 = /[a-z]+?/g;//所有符合条件的都替换了
console.log(str.replace(patter3,'我'));//'我我我我我我我我我我我'

贪婪和惰性的小案例:惰性+全局

let str = 'IloveYou I520You I爱You';
//要求:将I和You中间的字符加粗输出到页面:
//需要这个效果: <b>love</b>  <b>520</b>  <b>爱</b>
let patter = /I(.*)You/;
// document.write(str.replace(patter,'<b>$1</b>'));
//返回:<b>loveYou I520You I爱</b>
//patter模型使用了贪婪,匹配到了: loveYou I520You I爱
//没有达到要求

//使用惰性+全局
let patter1 = /I(.*?)You/g;//使用惰性+全局
document.write(str.replace(patter1,'<b>$1</b>'));
// <b>love</b>  <b>520</b>  <b>爱</b>

# 七、正则表达式使用 exec 返回数组

let str = 'HappyNewYear 2024';
let patter1 = /^[a-zA-Z]+\s[0-9]+$/;//  /^[a-zA-Z]+\s\d+$/
let patter2 = /^[a-z]+\s[0-9]+$/i;
console.log(patter1.test(str));//true
//1. exec 返回包含字符串的数组
console.log(patter2.exec(str));//返回包含字符串的数组
console.log(Array.isArray(patter2.exec(str)));//true

//2.只匹配到字母
let patter3 = /^[a-zA-Z]+/;
console.log(patter3.exec(str));//["HappyNewYear"]

//3.使用了分组
let patter4 = /^([a-zA-Z]+)\s([0-9]+)$/;
console.log(patter4.exec(str));//['HappyNewYear 2024','HappyNewYear','2024']
//使用分组之后的返回值说明,依次如下:
//1. 返回匹配到的整个字符串
//2. 返回匹配到的第一个分组的字符串
//3. 返回匹配到的第二个分组的字符串

# 八、捕获性分组和非捕获性分组

let str = 'HappyNewYear2024';
let patter = /([a-zA-Z]+)(\d+)/;
console.log(patter.exec(str));//['HappyNewYear2024','HappyNewYear','2024']
//这个叫做捕获性分组,所有的分组都捕获返回了
 
//非捕获性分组
let patter1 = /(?:[a-zA-Z]+)(\d+)/;
console.log(patter1.exec(str));//['HappyNewYear2024','2024']
//非捕获性分组,只要在不需要捕获返回的分组上加上: ?:
//1.返回匹配到的整个字符串
//2.返回没有加 ?:的分组
//就是你不想捕获哪个分组,就在分组里面的前面加上 ?:

# 九、分组嵌套、前瞻捕获、特殊字符匹配、换行模式

分组嵌套(?(?(?)))

//分组嵌套,从外往内获取
let patter = /(你?(爱?(我?)))/;
let str = '你爱我';
console.log(patter.exec(str));//['你爱我', '你爱我', '爱我', '我']
//1. 整个匹配到的字符串 '你爱我'
//2. 匹配第一个分组(你?(爱?(我?))),匹配到 '你爱我'
//3. 匹配第二个分组(爱?(我?),匹配到 '爱我'
//4. 匹配第三个分组(我?),匹配到 '我'

前瞻捕获

//前瞻捕获(?=)
let patter = /google/;
console.log(patter.exec('google'));// ['google']
//如果要返回goo, 此时修改一下模式
let patter1 = /goo/;
console.log(patter1.exec('google'));//['goo']
console.log(patter1.exec('goobbb'));//['goo']
//问题出现了,我只能让 'google'的字符串返回 goo
//使用前瞻捕获
let patter2 = /goo(?=gle)/;
console.log(patter2.exec('goobbb'));//null
console.log(patter2.exec('google'));//['goo']
//goo后面必须是gle才能返回goo
//这里一定注意,返回的是 goo,而不是 google,这个就是前瞻捕获

特殊字符匹配: 用反斜杠\来转义正则表达式的特殊字符

let str = '[';//特殊字符
let patter = /\[/;
console.log(patter.test(str));//true

换行模式

let str = '1 吃饭\n2 睡觉\n3 钓鱼';
//alert(str);
//把数字换成#
let patter = /\d+/g;//全局替换
//但很多时候我们写的时候需要限定首尾
let patter1 = /^\d+/gm;//全局+换行匹配
alert(str.replace(patter1,'#'));

# 十、书写常用正则表达式

# ① 手机号正则

梳理一下手机号规则:目前手机号13开头、145/147开头、150-153,155-159、170/173/175-178、180-189、166、198、199开头,匹配大多数中国大陆的手机号码,包括 13、14、15、17、18 开头的手机号码, 以及 166、198、199 开头的虚拟运营商的手机号码

/^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199)\d{8}$/

# ② 邮政编码正则

共 6 位数字,第一位不能为 0

//检查邮政编码: 共 6 位数字,第一位不能为 0
let patter = /^[1-9][0-9]{5}$/; //  /[1-9]\d{5}/
console.log(patter.test('432600'));//true

# ③ 简单的电子邮件正则

//简单电子邮件  51yrc.com@gmail.com
//规定:邮箱用户名:字母、数字、下划线、点号、-
//域名:字母、数字、下划线、- , 没有点号
//域名后缀:2-4位字母,com.cn这样的排除不算
// let patter = /^([a-zA-Z0-9_\.\-]+)@([a-zA-Z0-9_\-]+)\.([a-zA-Z]{2,4})$/;
let patter = /^([\w\.\-]+)@([\w\-]+)\.([a-zA-Z]{2,4})$/;
console.log(patter.test('51yrc.com@gmail.com'));//true
console.log(patter.test('docs.51yrc.com@163.cn'));//true
//以上是简单电子邮件,复杂的邮件大家可以去搜索,重点看你对电子邮件的格式规定

# ④ 匹配图片格式

图片格式: jpg,png,gif,jpeg,然后我们规定:图片名字必须是: 字母或数字或者下划线

//图片格式: jpg,png,gif,jpeg
//然后我们规定:图片名字必须是: 字母或数字或者下划线[a-zA-Z0-9_]  \w 
// _my01.png  you.jpg  _1.gif   15.jpeg
let patter = /^\w+\.(jpg|png|gif|jpeg)$/;
console.log(patter.test('_my01.png'));//true
console.log(patter.test('you.jpg'));//true
console.log(patter.test('_1.gif'));//true
console.log(patter.test('15.jpeg'));//true

# ⑤ 删除多余空格

//删除多余空格
let str = '111 222 333';
let patter = /\s/g; //g 必须全局,才能全部匹配
console.log(str.replace(patter,''));//'111222333'

# ⑥ 删除首尾的空格,中间的空格不删除

  1. 正常处理
//删除首尾的空格,中间的空格不删除
//'   I love YOU!  MISS GAO '=> 'I love YOU!  MISS GAO'
let str = '   I love YOU!  MISS GAO    ';
let patter1 = /^\s+/;
let res = str.replace(patter1,'');
console.log("|" +  res + "|");//'|I love YOU!  MISS GAO    |'
let patter2 = /\s+$/;
res = res.replace(patter2,'');
console.log("|" +  res + "|");//'|I love YOU!  MISS GAO|'
  1. 惰性模式处理
//删除首尾的空格,中间的空格不删除
//'   I love YOU!  MISS GAO '=> 'I love YOU!  MISS GAO'
let str = '   I love YOU!  MISS GAO    ';
//使用非贪婪捕获
let patter = /^\s+(.+)\s+$/;
// let res = patter.exec(str);
// console.log(res);//["   I love YOU!  MISS GAO    ","I love YOU!  MISS GAO   "]
let res = patter.exec(str)[1];
console.log('|' +  res + '|');//'|I love YOU!  MISS GAO   |'
// (.+)是贪婪模式,它将后面的空格都匹配上了
//应该使用惰性模式,适可而止
let patter1 = /^\s+(.+?)\s+$/;
let res1 = patter1.exec(str)[1];
console.log('|' +  res1 + '|');//'|I love YOU!  MISS GAO|'
  1. 惰性+分组快速获取
//删除首尾的空格,中间的空格不删除
//'   I love YOU!  MISS GAO '=> 'I love YOU!  MISS GAO'
let str = '   I love YOU!  MISS GAO    ';
//分组获取
let patter1 = /^\s+(.+?)\s+$/;
let res1 = str.replace(patter1,'$1');
console.log('|' +  res1 + '|');//'|I love YOU!  MISS GAO|'

# ⑦ 延伸:将11位手机号中的4-7位号码换成 *

//将11位手机号中的4-7位号码换成 * 
// 13858584458 => 138****4458
let patter = /^(\d{3})(\d{4})(\d{4})$/;
let str = '13858584458';
console.log(str.replace(patter,'$1****$3'));// '138****4458'

说明: 关于正则表达式的基础知识,我们先讲到这里,这些基础知识已经能够满足我们开发中的大部分需求,更高级的知识,随着我们之后项目的深入,再给大家讲解。







# 【第二学期第2季课程】其它章节

# 章节1.课程介绍

# 章节2.面向对象与原型

# 1、创建对象

# ① 创建对象,剖析问题:传统创建对象方法代码重复冗余,对象无法识别从属于哪个函数
# ② 传统创建对象:工厂模式(没有办法识别某一个对象的引用)
# ③ 构造函数(构造方法)创建特定的对象
# ④ 构造函数知识扩展,对象冒充构造函数,构造函数体内的函数返回值相等,但引用地址不相同

# 2、原型

# ① 原型创建对象
# ② 构造函数与原型对比,深度解析(图片示例)
# ③ isPrototypeOf()方法:判断一个对象是否指向了该构造函数的原型对象
# ④ 原型模式的执行流程(顺序):先实例,在构造函数,最后原型
# ⑤ 删除实例属性访问原型属性:delete方法
# ⑥ hasOwnProperty()方法检测属性是否存在实例中,in操作符判断属性是否存在于实例或原型中,两者结合判断属性是否只存在原型中
# ⑦ 原型创建对象字面量声明方式
# ⑧ 原型创建对象字面量声明方式,原型的声明是有先后顺序,重写原型会覆盖(切断)之前的原型
# ⑨ 内置引用类型:String,Number,Array等本身也使用了原型
# ⑩ 原型创建对象缺点剖析:传参和引用共享问题
# ⑪ 组合构造函数+原型模式:解决 ⑩ 构造传参和引用共享问题
# ⑫ 动态原型模式:解决 ⑪ 组合构造函数+原型模式,代码封装在一起,一种封装的感觉
# ⑬ 寄生构造函数:工厂模式 + 构造函数【备胎模式(了解)】
# ⑭ 稳妥构造函数(了解即可):在一些安全的环境中,比如禁止使用 this 和 new,就是寄生构造函数不能用new

# 3、继承

# ① js的继承方式通过原型链完成
# ② 继承父类属性方法的继承顺序:就近原则(实例化-->构造函数实例属性方法-->原型属性方法)
# ③ 继承后的实例从属关系
# ④ 对象冒充继承及问题:原型里面的属性方法无法继承
# ⑤ 组合继承【广泛应用】:原型链+借用构造函数(对象冒充)的模式,完成对象冒充的原型继承
# ⑥ 原型式继承(了解)
# ⑦ 寄生式继承:原型式+工厂模式结合
# ⑧ 继承终极版模式:寄生组合继承来实现继承:组合模式 + 寄生式继承

# 4、类和对象

# ① 理解类和对象
# ② 类中的constructor()方法(构造函数)
# ③ 类中添加方法
# ④ 类的继承
# ⑤ 类的继承中的super关键字:调用父类的构造函数constructor
# ⑥ 类的继承中的super关键字:调用父类的普通函数
# ⑦ 子类继承父类方法同时扩展自己的方法,子类在构造函数中使用super,必须放到this前面
# ⑧ 类和对象的几个注意点:

# 5、面向对象、原型、继承、类小结

# 章节3.封装js库过渡到jQuery

# 章节4.jQuery

# 1、代码风格:$包裹,加载模式:$(function () {}),获取元素DOM对象:get(索引)方法,多个库之间的冲突

# 2、选择器:

# ① ID 选择器、元素选择器、类(class)选择器,属性 length 或 size()方法来查看返回的元素个数
# ② jQuery对象转成DOM对象:get方法或下标获取
# ③ 群组选择器、后代选择器、通配选择器、指定元素前缀选择器
# ④ 层次选择器:jQuery提供后代选择器find、子选择器children、next 选择器、nextAll 选择器
# ⑤ jQuery提供:prev同级上一个元素,prevAll同级所有上面的元素
# ⑥ jQuery提供:siblings()方法:上下同级所有元素,正好集成了 prevAll()和 nextAll()两个功能的效果
# ⑦ jQuery提供:nextUntil()方法:查找同级后面的节点,遇到指定元素停止选定,prevUntil()方法:查找同级前面的节点,遇到指定元素停止选定
# ⑧ 属性选择器:一般超链接用得多点

# 3、过滤器(伪类选择器)

# ① :first,选取第一个元素,返回单个元素,jQuery提供first()方法
# ② jQuery对象转成DOM对象:get方法或下标获取
# ③:not(selector), :not(.active)选取class不是active的元素,返回元素集合,jQuery提供not(selector)方法
# ④ :eq(index),选择索引(0 开始)等于 index 的元素,返回单个元素,jQuery提供eq()方法
# ⑤ :gt(index),选择索引(0 开始)大于 index 的元素,返回元素集合
# ⑥ :lt(index),选择索引(0 开始)小于 index 的元素,返回元素集合
# ⑦ :even,选择索引(0 开始)是偶数的所有元素,返回元素集合
# ⑧ :odd,选择索引(0 开始)是奇数的所有元素,返回元素集合
# ⑨ :header,选择标题元素,h1 ~ h6,返回元素集合
# ⑩ :focus,选择当前被焦点的元素,一般用在表单元素上

# 4、内容过滤器

# ① :contains(text),选取含有text文本的元素,返回元素集合
# ② :empty,选取不包含子元素或空文本的元素,返回元素集合
# ③ :has(selector),如::has(.active) 选择后代元素含有class 是active 的元素,jQuery提供has()方法
# ④ :parent,与:empty刚好相反,选取含有子元素或文本的元素,返回元素集合

# 5、jQuery提供:parent()、parents()、parentsUntil方法特别说明

# ① jQuery提供:parent()方法:选取当前元素的父元素,注意与 :parent的区别
# ② jQuery提供:parents()方法:选择当前元素的父元素及祖先元素
# ③ jQuery提供:parentsUntil方法,如:parentsUntil('ul') 选择当前元素往上一层级查找,遇到ul元素停止

# 6、可见性过滤器

# ① :hidden,选取所有不可见元素,返回元素集合,一般包含:CSS 样式为 display:none、input 表单类型为type="hidden"和 visibility:hidden 的元素
# ② :visible,选取所有可见元素

# 7、子元素过滤器

# ① :first-child,获取每个父元素的第一个子元素,返回元素集合
# ② :last-child,获取每个父元素的最后一个子元素,返回元素集合
# ③ :only-child,获取只有一个子元素的元素,返回元素集合
# ④ :nth-child(odd/even/eq(index)),获取每个自定义子元素的元素(索引值从 1 开始计算)

# 8、jQuery提供选择器和过滤器方法

# ① is()方法:传递选择器、DOM、jquery 对象、函数
# ② hasClass方法,hasClass(); hasClass(class),判断某个元素是否有某个class,比较常用,和 is 一样,只不过只能传递class
# ③ slice方法,slice(start, end),选择从 start 到 end 位置的元素,如果是负数,则从后开始
# ④ end方法,end(),获取当前元素前一次状态:可以找它的父节点,也可以找它的相邻前一个兄弟节点
# ⑤ contents方法,contents(),获取某元素下面所有元素节点,包括文本节点,如果是 iframe,则可以查找文本内容
# ⑥ filter方法,filter(),比较灵活的选择器,扩展性较好

# 9、表单选择器

# ① jQuery方法:通过type类型或者name字段获取表单组件,通过val()方法获取表单组件的值

# 10、jQuery操作DOM及CSS

# 1、设置元素及内容:html(),html(value),text(),text(value)
# 2、获取或设置表单内容:val(),val(value)
# 3、设置单选框、复选框默认选中状态val(),非常好用
# 4、元素属性操作:attr()和 removeAttr()
# 5、元素CSS样式操作
# Ⅰ、css()方法
# ① css()方法获取、设置元素样式
# ② css()方法传递多个样式属性的数组,得到样式属性值对象数组,$.each(box,function(attr,value){})遍历原生态对象数组,jQuery对象数组采用$(selector).each(function(index,element){})方法遍历
# ③ css()方法传递多个 CSS 样式的键值对
# ④ css()方法可以传匿名函数
# Ⅱ、addClass()方法、removeClass()方法、toggleClass()方法
# ① addClass()方法、removeClass()方法
# ② toggleClass()方法:切换class
# Ⅲ、jQuery提供其他css操作方法
# ① jQuery提供:width()、width(value)、width(function (index, width) {})方法:获取、设置、通过匿名函数设置某个元素的长度
# ② jQuery提供:height()、height(value)、height(function (index, width) {})方法:获取、设置、通过匿名函数设置某个元素的高度
# ③ jQuery提供内外边距和边框尺寸方法:innerWidth(),innerHeight(),outerWidth(),outerHeight(),outerWidth(ture),outerHeight(true)
# ④ jQuery提供元素偏移方法:offset()、position()、scrollTop()、scrollTop(value)、scrollLeft()、scrollLeft(value)

# 11、jQuery提供的DOM节点操作方法

# 1、创建节点
# 2、插入节点
# ① 内部插入节点 append(content):向指定元素内部后面插入节点content
# ② 内部移入节点(不需要创建节点) appendTo(content):将指定元素移入到指定元素content 内部后面
# ③ 内部插入节点 prepend(content):向指定元素 content 内部的前面插入节点
# ④ 内部移入节点(不需要创建节点) prependTo(content):将指定元素移入到指定元素content 内部前面
# ⑤ 外部(同级)插入节点 before(content):向指定元素的外部前面插入节点content
# ⑥ 外部(同级)移到节点 (不需要创建节点)insertBefore(content):将指定节点移到指定元素content 外部的前面
# ⑦ 外部(同级)插入节点 after(content):向指定元素的外部后面插入节点content
# ⑧ 外部(同级)移到节点 (不需要创建节点)insertAfter(content):将指定节点移到指定元素content 外部的后面
# 3、包裹节点
# ① wrap(html):向指定元素包裹一层html 代码
# ② wrap(element):向指定元素包裹一层 DOM对象节点
# ③ wrap(function (index) {}):使用匿名函数向指定元素包裹一层自定义内容
# ④ unwrap():移除一层指定元素包裹的内容
# ⑤ wrapAll(html):用 html 将所有元素包裹到一起
# ⑥ wrapAll(element):用 DOM 对象将所有元素包裹在一起
# ⑦ wrapInner(html)、wrapInner(element)、wrapInner(function (index) {}):向指定元素的子内容包裹一层
# 4、节点操作
# ① 复制节点 clone(true)、替换节点:replaceWith、replaceAll
# ② 删除节点:remove() 或者 detach()
# ③ 删除掉节点里的内容empty()

# 章节5.jQuery事件、动画、插件

# 一、事件

# 1、简写事件

# 2、复合事件:hover([fn1,]fn2)

# 3、jQuery中的事件对象:target、currentTarget、e.stopPropagation()、e.preventDefault()、return false

# 4、jQuery中的高级事件:on、off 和 one

# ① on方法
# ② off方法:移除事件
# ③ one方法:仅触发一次的事件

# 5、jQuery中的模拟操作

# 二、动画

# 1、 显示:show、隐藏:hide

# ① 直接调用:显示show()、隐藏:hide()
# ② 传递一个参数(毫秒):显示show(1000)、隐藏:hide(1000)
# ③ 传递一个预设参数:显示show(slow|normal|fast),隐藏:hide(slow|normal|fast),slow:600 毫秒,normal:默认 400 毫秒,fast:200 毫秒
# ④ 传递第二个参数回调函数,实现列队动画(排队动画):show(毫秒数|slow|normal|fast,function(){}),hide(毫秒数|slow|normal|fast,function(){})
# ⑤ 列队动画,可以使用函数名调用自身或者arguments.callee 匿名函数自调用
# ⑥ toggle()切换show()和hide()

# 2、 滑动:slideUp、卷动:slideDown、切换滑动卷动:slideToggle

# 3、 淡入:fadeIn、淡出:fadeOut、切换淡入淡出:fadeToggle、指定透明度:fadeTo

# 4、 自定义动画 animate

# ① animate基本用法:css样式自定义,同步动画
# ② animate用法:animate(css,动画时间,回调函数)
# ③ animate位移动画(将元素设置绝对定位或相对定位)
# ④ 列队动画方法:queue()方法,连缀执行下一个dequeue()方法,clearQueue()清理列队动画后面还没有执行的

# 5、 动画相关方法:stop()强制停止动画,delay()延迟动画执行

# 6、判断在运动的动画,通过过滤器:animated

# 7、动画全局属性:$.fx.interval(设置每秒运行的帧数),$.fx.off(关闭页面上所有的动画),默认swing(缓动),linear(匀速运动)

# 三、jQuery插件

# 1、引入:下载本地引入、或在线引入

# 2、使用插件方法

# 章节6.Ajax

# 一、原生js中的Ajax

# 1、XMLHttpRequest (简称 XHR,XHR API)

# ① 第一步:调用 open()方法准备发送请求(发送请求前的准备工作):三个参数:要发送的请求类型(get、post)、请求的 URL 和表示是否异步
# ② 第二步:通过 send()方法进行发送请求:一个参数:作为请求主体发送的数据,如果不需要则,必须填 null
# ③ 第三步:发送完了之后,得监听结果(监听服务器给你的请求结果),通过readystatechange 事件监听服务器给你的结果

# 2、理解get、post请求

# ① getAllResponseHeaders()获取整个响应头信息,getResponseHeader()获取单个响应头信息,setRequestHeader()设置请求头信息
# ② get请求
# ③ post请求
# ④ 小结get和post请求

# 3、Fetch API

# ① Fetch API基本用法介绍
# ② XHR 与 Fetch 中的Content-Type(或者小写content-type)

# 4、 XHR(xhr) 与 Fetch(fetch)的区别 (包括:jQuery、Axios、umi-request的说明)

# 二、jQuery中的Ajax

# 1、第二层封装:load()方法,$.get()和$.post()方法

# ① load()方法是局部方法 : 异步加载静态文件如:html文件、json文件等
# ② $.get()和$.post()方法:是全局方法,无须指定某个元素,适合传递参数到服务器请求数据

# 2、最高层封装:$.getJSON() 和 $.getScript()

# ① $.getJSON()方法:专门用于加载 JSON 文件的
# ② $.getScript()方法:按需加载接口或js文件

# 3、最底层的封装:$.ajax()

# 4、表单序列化

# ① 常规形式的表单提交(表单提交数据)
# ② jQuery中的表单序列化提交数据(表单提交数据)
# ③ $.param()方法将对象转换为字符串键值对格式

# 5、jQuery中的跨域jsonp

# ① jQuery中的跨域jsonp使用
# ② 延伸一下:jQuery中的跨域jsonp模拟百度搜索提示数据

# 6、 jqXHR 对象: when()方法、done()方法、always()方法和fail()方法

# 章节7.Node.js基础

# 一、Node环境搭建(安装node.js)

# 1、 下载安装node.js

# 2、 检查node.js是否安装成功

# ① 命令行:node -v npm -v npx -v
# ② 命令行:node 运行js代码
# ③ 命令行:运行js文件代码,清屏命令: cls

# 二、NVM(node版本管理工具,切换node版本)

# 1、 下载安装nvm

# 2、检查nvm是否安装成功:nvm -v

# 3、设置nodejs、npm下载源(可选)

# 4、使用NVM包管理器

# 三、NPM包管理(npm包管理工具)

# 1、 package.json 文件如何生成

# 2、 NPM (npm) 、 CNPM (cnpm)

# 1、npm
# 2、cnpm (可选)
# ① 安装cnpm
# ② 接下来就可以使用cnpm命令安装各个包、插件、模块等等
# ③ 在vscode中运行命令
# ④ npm 或 cnpm 常用命令

# 四、Node的模块

# 1、全局模块 :process为例

# 2、系统模块 : path、fs模块为例

# 3、 自定义模块: exports、module输出、require引入

# 4、 重要系统模块:http模块,搭建网页服务器

# 五、Node中的数据交互,重要系统模块:url模块处理get请求,querystring模块处理post请求

# 1、url模块处理GET(get)请求:url.parse(url,true)

# 2、querystring模块处理POST(post)请求:querystring.parse()

# 六、nodejs项目监测文件变化,自动重启工具:Nodemon

# 1、安装nodemon

# 2、修改package.json 中的启动命令

# 3、配置nodemon,告诉它哪些文件需要修改后重启服务(可选项)

# 七、nrm (使用nrm管理npm下载源)

# 1、安装nrm

# 2、nrm内置的命令函数

# 3、查看当前正在使用的 npm 镜像源

# 4、切换 npm 镜像源

# 八、系统模块:fs模块详解

# 1、读取文件: 异步readFile、同步readFileSync、promise操作

# 2、可读流模式:createReadStream()方法

# 3、创建文件夹:mkdirSync , mkdir

# 4、删除文件夹:rmSync , rm

# 5、重命名文件:renameSync , rename

# 6、监听文件变化: watch

# 7、写入文件:writeFile、writeFileSync,追加写入文件:appendFile、appendFileSync

# 8、写入文件:创建可写流 createWriteStream()

# 九、node.js + jQuery完成:网页 “联系我们” 页面的留言板功能

# 十、系统模块:crypto模块详解(加密:对称加密、非对称加密、哈希函数)

# 1、对称加密、封装加密函数

# 2、非对称加密

# 3、哈希函数加密

# 4、对留言板的手机号做一个加密

# 章节8.正则表达式

# 一、创建正则表达式

# ① new运算符创建正则表达式

# ② 字面量方式创建正则表达式

# 二、测试正则表达式

# ① test方法:在字符串中测试模式匹配,返回 true 或 false

# ② exec方法:在字符串中执行匹配搜索,返回结果数组,执行失败,则返回 null

# 三、字符串的正则表达式方法

# ① match方法:就是一个查找的功能,获取匹配的字符串,返回数组或 null

# ② search方法:根据匹配的字符串,返回位置索引(从0开始)

# ③ split方法:按照匹配模式,拆分成字符串数组

# ④ replace方法: 替换匹配到的数据

# 小案例:模拟百度搜索,搜索的关键字设置成红色

# 四、正则表达式RegExp对象的静态属性、实例属性(了解)

# 1、 静态属性

# ① 属性:input,短名:$_ , 当前被匹配的字符串
# ② 属性:leftContext,短名:$` , 最后一次匹配前的子串
# ③ 属性:rightContext,短名:$' , 在上次匹配之后的子串
# ④ 属性:lastMatch,短名:$& , 最后一个匹配字符串
# ⑤ 属性:lastParen,短名:$+ , 最后一对圆括号内的匹配子串

# 2、 实例属性

# 五、正则表达式元字符(包含特殊含义的字符)

# 一、 单个字符和数字、重复字符

# 1、 点符号匹配除了换行符(\n)外的任意字符

# 2、 点符号和重复字符配合使用

# ① 重复字符:x?,表示:匹配 0 个或 1 个 x (x可以换成任意字符)
# ② 重复字符:x*,表示:匹配 0 个或 1 个 或者任意多个 x (x可以换成任意字符)
# ③ 重复字符:x+,表示:匹配 至少1个 或者任意多个 x (x可以换成任意字符)
# ④ 重复字符:x{m,n},表示:匹配最少 m 个、最多 n 个 x, x{m}表示:只能有m个x, x{m,}表示:有m个x或者以上个x (x可以换成任意字符)
# ⑤ 重复字符:(xyz)+,表示:匹配至少一个(xyz),括号可以看成分组,分组里面的元素可以是任意多个字符
# ⑥ 任意一个匹配:[a-z]匹配26个小写字母任意一个,[A-Z]匹配26个大写字母任意一个,[0-9]匹配0到9的数字任意一个,[a-zA-Z0-9]匹配混合字母和数字中的任意一个
# ⑦ 任意一个不匹配:[^a-z]不匹配26个小写字母,[^A-Z]不匹配26个大写字母,[^0-9]不匹配0到9的数字,[^a-zA-Z0-9]不匹配混合字母和数字

# 3、字符类:锚字符

# ① 锚字符:^ , 表示:从行首开始匹配
# ② 锚字符:$ , 表示:从行尾开始匹配

# 4、字符:\d , 匹配数字,和字符集合 [0-9]相同,字符:\D , 匹配非数字,同[^0-9]相同

# 5、字符:\w , 匹配字母和数字及_,和字符集合 [a-zA-Z0-9_]相同,字符:\W , 匹配非字母和数字及_,同[^a-zA-Z0-9_]相同

# 二、空白字符

# ① 字符:\s,表示:匹配空白字符、空格、制表符和换行符

# ② 字符:\b,表示:到达边界

# 三、选择字符(|)选择模式,匹配如:jpg|png|gif,非相等包含的意思

# 四、分组模式:()做分组,\1或$1匹配第一个分组中的内容,\2或$2匹配第二个分组中的内容,依次类推

# ① 分组模式:()做分组

# ② $1可以获取到第一个分组内容

# ③ 小案例:$1获取到第一个分组内容,并做替换

# ④ 小案例:获取多个分组内容,进行替换

# 六、正则表达式:贪婪和惰性

# 七、正则表达式使用 exec 返回数组

# 八、捕获性分组和非捕获性分组

# 九、分组嵌套、前瞻捕获、特殊字符匹配、换行模式

# 十、书写常用正则表达式

# ① 手机号正则

# ② 邮政编码正则

# ③ 简单的电子邮件正则

# ④ 匹配图片格式

# ⑤ 删除多余空格

# ⑥ 删除首尾的空格,中间的空格不删除

# ⑦ 延伸:将11位手机号中的4-7位号码换成 *

# 章节9.Vue.js基础

# 一、课前准备:启动node服务器,引入vue.js

# 二、体验vue的数据响应式:① 配置项data中的数据响应式,及渲染到页面上的真实DOM效果、② 循环语句,事件处理体验、③ vuejs计算属性体验

# 三、理解vue的注入、虚拟DOM及底层原理:vue实例成员的注入、虚拟DOM、虚拟DOM的底层原理

# 四、案例:node.js + vue.js 渲染企业网站



# 其它学期课程

# 第一学期(学习顺序:01)

第一学期课程专为零基础的学员定制录制的,纯html+css做企业网站的网页,主讲html和css的相关基础知识,flex布局相关知识,封装css基础样式库,引入字体图标及网页开发基础布局思维,完成企业网站网页的开发过程。

[第一学期学习视频]

# 第二学期【第1季】(学习顺序:02)

主讲JavaScript的基础,建议所有学员观看。
[第1季学习文档] [第1季学习视频]

# 第二学期【第2季】(学习顺序:03)

JavaScript中的面向对象,类,ajax,封装js库过渡到jQuery, vue.js基础配置网站页面,建议所有学员观看。
[第2季学习文档] [第2季学习视频]

# 第二学期【第3季】(学习顺序:04)

egg.js基础,响应式网页布局,Bootstrap框架,响应式后台系统管理,完整企业网站前后台开发,建议所有学员观看。
[第3季学习文档] [第3季学习视频]

# 第二学期【第4季】(学习顺序:05)

主要对第三季,同学们开发的企业网站,进行一个完整的上线运维流程的一个讲解,同学们将网站开发完成之后,如何进行上线运维,将项目交付给客户。
[第4季学习文档] [第4季学习视频]

更新时间: 2024年11月19日星期二中午11点54分