前言:这一篇文章主要讲解JavaScript高级的知识,涉及到原型,类,继承,模块化,正则匹配,以及promise的使用,还会了解到一些鼠标键盘事件以及关于前端页面内容的知识。学完这些你可以去学typescript了,加油呀
目录
一:原型:一个对象
原型链:
设置原型链
设置一个对象作为另一个对象的原型:
设置对象的原型:
原型是一个对象:
原型链的意义:
合理的构造函数声明:
原型链方法的借用:call等方法
this不受原型的影响:
不要滥用添加原型方法:
原型链的检测:
原型链的继承:
理解:
类:
类的定义
类的特点:
类的属性:
静态属性static
静态方法:
练习demo:
类的属性保护:
类的继承:
属性和方法的继承:super
super使用规则:
静态static的继承:
类的混合:
类的综合使用:
总结:
怎么使用类的成员方法:
怎么区别是用静态关键字:
模块化:
根据es6的模块化规则:
模块化的特点:
模块作用域:
导出:
具名导出:
默认导出:
导入:
具名导入:
批量导入:
webpack打包:
正则:
用处:
对比:
创建正则:
字面量形式:
对象形式:
例子:
转义 反斜杠 \:
字符边界
数值与空白符:
模式修正符:
m 换行demo:
u:
u demo
#lastIndex
贪婪匹配字符:
贪婪匹配:匹配贪婪字符前一个字符的多个
禁止贪婪:在贪婪匹配的规则后面加?
原子表 [ ]:
原子组 ( ):
引用分组:
多个正则校验思路:
正则方法:
exec;检索字符串,还不如用match
test:检索返回布尔值
关于正则的字符串方法:
search:返回索引
match:匹配出符合要求的字符串
matchAll:检索出符合要求的迭代对象,配合全局g使用
split:分割,括号里面可以写正则
replace:替换方法,常用于字符串的增删改查,配合正则*******
断言匹配:
Promise:
一:原型:一个对象
原型洽淡的比喻就是你的父亲,原型链就是家族谱。你可以找你父亲要点什么,你父亲可以找你爷爷要点什么,你在js中普通定义的变量都不是孤儿。
show: ƒ show() 自己原型·:父亲1 服务于实例化的对象,例如使用构造函数生成的实例******重要
[[Prototype]]: Object
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()原型:父亲2 服务于本身这个对象
__proto__: Object
constructor: ƒ Object()
assign: ƒ assign()
create: ƒ create()
你可以调用一些方法,可能你本身没有,所以你去找原型父亲身上看看有没有,有的话就能使用父亲的方法。如果你自己本身有属性方法和父亲有相同的名字的方法,你的优先级更大,因为你有钱了就不会去找父亲要钱。
原型链:
根据原型链的规则,实例对象的-proyo-他是等于构造函数的prototype的
意思就是:每个实例身上都有 __proto__ 属性,它指向构造函数的 Prototype(Prototype这个属性是构造函数身上的属性,它服务于构造函数创造的实例) 。构造函数的 __proto__ 属性 直接指向上层的 Prototype ,最后OBject的 __proto__ 终点为null
设置原型链
设置一个对象作为另一个对象的原型:
使用Object.setPrototypeOf
可设置对象的原型,下面的示例中继承关系为 obj>hd>cms。
Object.getPrototypeOf
用于获取一个对象的原型。
let obj = {name: "后盾人"
};
let hd = {web: "houdunren"
};
let cms = {soft: "hdcms"
};
//让obj继承hd,即设置obj的原型为hd
Object.setPrototypeOf(obj, hd);
Object.setPrototypeOf(hd, cms);
console.log(obj.web);
console.log(Object.getPrototypeOf(hd) == cms); //true
能通过原型上的constructor找到构造函数
let c = Object.getPrototypeOf(a).constructor
设置对象的原型:
let user = {show() {return this.name;}
};let hd = Object.create(user); 把user作为hd的原型
hd.name = "向军";
console.log(hd.show());//向军
原型是一个对象:
-proto-这个东西其实是getter访问器,设置它的值只能是一个原型对象,因为setter做了限制,如果说你想跳过原型,仅仅只把它当作属性,可以把当前对象的原型去掉
let obj = Object.create(null)//obj没有原型obj._proto_=999//这个就只是个属性了
原型链的意义:
合理的构造函数声明:
构造函数构造对象,不要在构造函数里面写属性方法,容易内存开销,建议写在构造函数的Prototype属性上,提供给对象使用。
function created(name){this.name =name}created.prototype={constructor:created,show(){console.log(this.name);}}const obj = new created("yy")const obj2 = new created("aa")obj.show()//obj这个对象能使用构造函数原型上的show方法,可以避免构造函数构造对象内存消耗obj2.show()
就是 在父级对象定义方法,他的后代可以继承使用。就方便快捷一点。
原型链方法的借用:call等方法
理解:比如你家没有车,你去问邻居借
Math.max.apply(null,arr) //借用Math对象身上的max属性方法,通过apply改变传过去的对象。
this不受原型的影响:
let a = {name: 1,};let b = {name: 2,g() {console.log(this.name);},};Object.setPrototypeOf(a, b);a.g(); //1
不要滥用添加原型方法:
容易冲突!
原型链的检测:
console.dir(a instanceof A); //true a继承A构造函数的原型链console.log(b.isPrototypeOf(a)); //true b是否是a的长辈,就是b下面有a,b的原型链下面有a
原型链的继承:
继承不是构造函数改变属性protype的指向,继承是-proto-原型的继承
理解:
- —proto— : 只要是一个对象实例,他就有这个属性去设置自己的原型
- —protype— :这个是构造函数身上的属性,他是服务于构造函数的实例,比如在这个属性上添加方法,可以给实例使用,但是构造函数也是个对象,它自己本身也是个对象实例,所以它也可以设置—proto—原型
- object.create会重新设置新的原型,而—proto—是改变原来原型的指向
类:
类的typeof其实是一个函数。本质也是一个函数,只是在面向对象编程时更加清晰,相当于原型的语法糖
类的定义
class User {类的属性,是所有实例对象所公共的属性name='yy';构造函数 加上this则为每个实例对象独享的属性constructor(name) {this.name = name;this.show = function () {};}类的方法,生成的实例对象可以调用,本质是原型protype上的方法,减少内存开销getName() {return this.name;}}
实例对象,自动调用constructor构造函数const xj = new User("向军大叔");console.log(xj);
类的特点:
constructor
方法会在 new 时自动执行- class定义的类方法在实例对象中不能遍历到
- 默认严格模式,普通function下的this指向underfined
- 类的this指向问题,一般来说谁调用了属性方法,this就指向谁
类的属性:
class User {name = 'yy'}let obj = new User()let obj2 = new User()obj.name = 'qq' //修改类的属性,不会影响到其他实例console.log('obj', obj) //{name: 'qq'}console.log('obj2', obj2) //{name: 'yy'}
静态属性static
原理:静态属性即为类设置属性,而不是为生成的对象设置
给所有实例对象都能用到,但是不属于实例对象,他的原理是属性class类的属性
- 可以把为所有对象使用的值,但是 实例对象访问不到该属性 定义为静态属性,
class User {static age = 22;constructor(name) {this.name = name;}getinfo() {return this.name + User.age}}const yy = new User('小鱼');// 静态属性不会给实例对象console.log(yy); // {name: '小鱼'}console.log('User.age', User.age) //22console.log('yy.getinfo()', yy.getinfo())//小鱼22
静态方法:
使用类名调用的方法为静态方法
指通过类访问不能使用对象访问的方法,比如系统的Math.round()
就是静态方法
- 一般来讲方法不需要对象属性参与计算就可以定义为静态方法
- 不针对单个对象操作
- 针对多个对象使用,即整个类使用,类去调用
class User {constructor(name) {this.name = name;}static create(name) {return new User(name);}
}通过类名User 调用静态方法create 传参,返回一个构造的实例对象
const xj = User.create("yy");
console.log(xj); {
name:‘yy’
}
练习demo:
let peoples = [{name: '邹昀',age: 25},{name: '单龙飞',age: 22},]class Dimine {constructor(info) {this.info = info;}// 适用属性访问器访问info对象的值get agea() {return this.info.age}//获取员工信息static getinfo(allInfo) {return allInfo.map(i => new Dimine(i))}//获取年龄最大的员工信息,该处使用了对象的访问器static getMaxage(v) {return Math.max(...v.map(i => i.agea))}}const message = Dimine.getinfo(peoples)console.dir(message)message的结构[{info: {name: '邹昀',age: 25}}, {info: {name: '单龙飞',age: 22},}]const Maxage = Dimine.getMaxage(message)console.log('Maxage', Maxage) //25
类的属性保护:
1:命名可以使用不一样的风格,比如加个下划线,然后通过访问器进行修改
_host = "https://houdunren.com";set host(url) {if (!/^https:\/\//i.test(url)) {throw new Error("网址错误");}this._host = url;}
2:利用semboy或着webpeb设置保护属性
3:private关键字 定义私有属性 简写 # 私有属性只能在当前声明类中使用
类的继承:
类的方法是在原型链上的,直接可以继承使用,属性是属于实例对象的,需要在构造函数里面使用super
super可以访问父级类
属性和方法的继承:super
class Person {constructor(name) {this.name = name;}show() {return `后盾人会员: ${this.name}`;}
}
class User extends Person {constructor(name) {super(name);}run() {利用super调用父级方法return super.show();}
}
const xj = new User("向军");
console.dir(xj.run());
super使用规则:
- 子类声明了构造函数,如果继承父类,必须写上super
- super必须写在子类构造函数this之前,防止父类覆盖子类
子类的方法优先级大于父类
静态static的继承:
子类可以直接调用父类静态属性
class User {static site = "后盾人";static host() {return "houdunren.com";}}class Admin extends User {}静态属性是通过类去调用console.log('User.site', User.site)//后盾人console.log('Admin.site', Admin.site)//后盾人
类的混合:
使用拷贝将对象拷贝在类的原型上面
Object.assign(Lesson.prototype, Tool);
类的综合使用:
<!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>Document</title><style>* {padding: 0;margin: 0;box-sizing: content-box;}body {padding: 30px;}.slide {width: 300px;display: flex;flex-direction: column;/* box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3); */}.slide dt {height: 30px;background: #34495e;color: white;display: flex;align-items: center;padding-left: 10px;cursor: pointer;}.slide dt:first-of-type {border-top-left-radius: 10px;border-top-right-radius: 10px;}.slide dd {height: 100px;background: #f1c40f;overflow: hidden;}.slide dd div {padding: 10px;}.slide dd:last-of-type {border-bottom-left-radius: 10px;border-bottom-right-radius: 10px;}</style><body><div class="slide s1"><dt>后盾人</dt><dd><div>houdunren.com</div></dd><dt>后盾人</dt><dd><div>hdcms.com</div></dd><dt>后盾人</dt><dd><div>hdcms.com</div></dd></div>
</body><script>
动画类class Animation {constructor(el) {this.el = el;this.timeout = 5;this.isShow = true;this.defaultHeight = this.height;}hide(callback) {this.isShow = false;let id = setInterval(() => {if (this.height <= 0) {clearInterval(id);callback && callback();return;}this.height = this.height - 1;}, this.timeout);}show(callback) {this.isShow = false;let id = setInterval(() => {if (this.height >= this.defaultHeight) {clearInterval(id);callback && callback();return;}this.height = this.height + 1;}, this.timeout);}get height() {return window.getComputedStyle(this.el).height.slice(0, -2) * 1;}set height(height) {this.el.style.height = height + "px";}}
操作类class Slide {constructor(el) {this.el = document.querySelector(el);this.links = this.el.querySelectorAll("dt");this.panels = [...this.el.querySelectorAll("dd")].map(item => new Panel(item));this.bind();}bind() {this.links.forEach((item, i) => {item.addEventListener("click", () => {this.action(i);});});}action(i) {Panel.hideAll(Panel.filter(this.panels, i), () => {this.panels[i].show();});}}
面板类继承动画类,达到使用动画类的方法class Panel extends Animation {static num = 0;static hideAll(items, callback) {if (Panel.num > 0) return;items.forEach(item => {Panel.num++;item.hide(() => {Panel.num--;});});callback && callback();}static filter(items, i) {return items.filter((item, index) => index != i);}}let hd = new Slide(".s1");console.log('hd', hd)
</script></html>
上面运用的dom操作,定时器,防抖,数组方法,回调函数,面向对象编程思路
总结:
怎么使用类的成员方法:
1:创建类的实例对象
2:继承父类,子类的实例对象可以使用
怎么区别是用静态关键字:
关于类的使用可以加上static
模块化:
使用模块化能避免一些作用域的问题。
根据es6的模块化规则:
- 使用
export
将开发的接口导出 - 使用
import
导入模块接口 - 使用
*
可以导入全部模块接口 - 如果导入写{}意思是你需要接受多个导出,如果导出只有一个,可以写默认导出。导入就不需要写{}
- 默认导出只是导出一个的情况,导入可以随便哪个变量名都可以接收,导出导入都不需要花括号!
- 导出是以引用方式导出,传址。无论是标量还是对象,即模块内部变量发生变化将影响已经导入的变量
- 别名导入导出,使用as替换
import { User as user, func as action, site as name } from "./hd.js";let func = "houdunren"; 这个时候下面就需要使用别名console.log(user);console.log(action);console.log(name);
模块化的特点:
- 严格模式
- 只执行一次,预解析
- 靠后执行
模块作用域:
类似于函数作用域,拥有独立作用域,且默认拥有严格模式
只有在导出和导入的时候,才能去访问到。两者缺一不可
导出:
export 总共导出一个对象或者单个具名导出
具名导出:
export const site = "后盾人";
export const func = function() {return "is a module function";
};
export class User {show() {console.log("user.show");}
}或者const site = "后盾人";
const func = function() {return "is a module function";
};
class User {show() {console.log("user.show");}
}
export { site, func, User };
默认导出:
只有一个需要导出时,可以设置默认导出
导出:不需要写{}
export default class User {static show() {console.log("User.method");}
}导入:也不需要{},同时变量可以随意定义,就代表导出的那个内容import User from "./hd.js";
导入:
import 导入一个对象 from “路劲”
具名导入:
import { User, site, func } from "./hd.js";
批量导入:
使用api这个变量来全部批量导入,缺点:不需要的你都导入进来了,显得臃肿效率低
import * as api from "./hd.js";api这个对象去找下面的属性console.log(api.site);console.log(api.User);
webpack打包:
将文件打包到dist目录下面。
正则:
用处是对字符串的增删改查!,操作字符串优先考虑正则,字符串的方法很多可以使用正则
用处:
- 用在字符串replace替换,font.replace(//,"")
- 用在字符串校验是否含有该元素,(//.test(font))返回布尔值
- 查找符合条件的字符串,拿出来font.match(reg)
对比:
常规:
let hd = "houdunren2200hdcms9988";
解构语法转为数组,利用判断是不是转换为数字类型然后实行数组过滤
let nums = [...hd].filter(a => !Number.isNaN(parseInt(a)));
console.log(nums.join(""));正则:
let hd = "houdunren2200hdcms9988";
console.log(hd.match(/\d/g).join(""));
创建正则:
字面量形式:
使用
//
包裹的字面量创建方式是推荐的作法,但它不能在其中使用变量
let hd = "houdunren.com";
console.log(/u/.test(hd));//true
对象形式:
当正则需要动态创建时使用对象方式
let hd = "houdunren.com";
let web = "houdunren";
let reg = new RegExp(web);
console.log(reg.test(hd)); //true
例子:
<body><div id="yy">今天是2022年</div>
</body><script>const enter = prompt('请输入要搜索的内容,支持正则表达式')// 创建字符串规则let zz = new RegExp(enter, 'g')let doc = document.querySelector('#yy')doc.innerHTML = doc.innerHTML.replace(zz, search => {return `<span style='color:red'>${search}</span>`})
</script>
转义 反斜杠 \:
利用\ 后加特殊字符实现转义。
字符边界
使用字符边界符用于控制匹配内容的开始与结束约定。
边界符 | 说明 |
---|---|
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束,忽略换行符 |
const hd = "www.houdunren.com";
console.log(/^www/.test(hd)); //true例子:<body><input type="text"><span></span>
</body><script>const input = document.querySelector('input');input.addEventListener('keyup', function () {let flag = this.value.match(/^[a-z]{3,6}$/)document.querySelector('span').innerHTML = flag ? '正确' : '失败'})
</script>
数值与空白符:
最基础的匹配字符。
元字符 | 说明 | 示例 |
---|---|---|
\d | 匹配任意一个数字 | [0-9] |
\D | 与除了数字以外的任何一个字符匹配 | [^0-9] |
\w | 与任意一个英文字母,数字或下划线匹配 | [a-zA-Z_] |
\W | 除了字母,数字或下划线外与任何字符匹配 | [^a-za-z_] |
\s | 任意一个空白字符匹配,如空格,制表符\t ,换行符\n | [\n\f\r\t\v] |
\S | 除了空白符外任意一个字符匹配 | [^\n\f\r\t\v] |
. | 匹配除换行符外的任意字符 |
大写的一般为 除了
模式修正符:
修饰符 | 说明 |
---|---|
i | 不区分大小写字母的匹配 |
g | 全局搜索所有匹配内容 |
m | 视为多行 |
s | 视为单行忽略换行符,使用. 可以匹配所有字符 |
y | 从 regexp.lastIndex 开始匹配,注意他会连续匹配,如果匹配不符合连续,则匹配结束 |
u | 正确处理四个字符的 UTF-16 编码,用来处理汉字或者全局大的匹配 |
m 换行demo:
let hd = `#1 js,200元 ##2 php,300元 ##9 houdunren.com # 后盾人#3 node.js,180元 #
`;let lessons = hd.match(/^\s*#\d+\s+.+\s+#$/gm).map(i => {[Lname, price] = i.replace(/\s*#\d+\s+/, '').replace(/\s+#/, '').split(',')return {Lname,price}})console.log('lessons', lessons)
u:
可以考虑用来匹配字母或者标点 或者中文
u demo
每个字符都有属性,如L
属性表示是字母,P
表示标点符号,需要结合 u
模式才有效。其他属性简写可以访问 属性的别名 (opens new window)网站查看。
使用\p{L}属性匹配字母
let hd = "houdunren2010.不断发布教程,加油!";
console.log(hd.match(/\p{L}+/u));使用\p{P}属性匹配标点
console.log(hd.match(/\p{P}+/gu));
字符也有 unicode 文字系统属性 Script=文字系统
,下面是使用 \p{sc=Han}
获取中文字符 han
为中文系统,其他语言请查看 文字语言表(opens new window)
let hd = `
张三:010-99999999,李四:020-88888888`;
let res = hd.match(/\p{sc=Han}+/gu);
console.log(res);['张三', '李四']
使用 u
模式可以正确处理四个字符的 UTF-16 字节编码
let str = "𝒳𝒴";
console.table(str.match(/[𝒳𝒴]/)); //结果为乱字符"�"console.table(str.match(/[𝒳𝒴]/u)); //结果正确 "𝒳"
#lastIndex
RegExp 对象lastIndex
属性可以返回或者设置正则表达式开始匹配的位置
- 必须结合
g
修饰符使用 - 对
exec
方法有效 - 匹配完成时,
lastIndex
会被重置为 0
let hd = `后盾人不断分享视频教程,后盾人网址是 houdunren.com`;
let reg = /后盾人(.{2})/g;
reg.lastIndex = 10; //从索引10开始搜索
console.log(reg.exec(hd));
console.log(reg.lastIndex);reg = /\p{sc=Han}/gu;
while ((res = reg.exec(hd))) {console.log(res[0]);
}
贪婪匹配字符:
贪婪匹配:匹配贪婪字符前一个字符的多个
+:一个或多个(贪婪),贪婪的放在一起
*:表示0个或多个
{}:花括号里面表示匹配几个,逗号相隔是几到几。逗号后面参数不写,表示无数。
?:问号代表0个或一个。表示存不存在。
匹配所有字符可以使用原子表
[\s\S]
或[\d\D]
贪婪匹配符号 | 说明 |
---|---|
* | 表示0个或多个 |
+ | 一个或多个(贪婪),贪婪的放在一起 |
? | 重复零次或一次 |
{n} | 重复 n 次 |
{n,} | 重复 n 次或更多次 |
{n,m} | 重复 n 到 m 次 |
禁止贪婪:在贪婪匹配的规则后面加?
尽可能的减少贪婪。往最低下限验证规则。比如*是0到多个,*?趋向0个
说明白点,就是禁止了你的贪婪。
let str = "aaa";
console.log(str.match(/a+/)); //aaa
console.log(str.match(/a+?/)); //a
console.log(str.match(/a{2,3}?/)); //aa
console.log(str.match(/a{2,}?/)); //aalet str = 'yu'let reg = /yu*?/gi;console.log('str.match(reg)', str.match(reg))//['y']
原子表 [ ]:
原子表 | 说明 |
---|---|
[] | 只匹配其中的一个原子 |
[^] | 只匹配"除了"其中字符的任意一个原子 |
[0-9] | 匹配 0-9 任何一个数字 |
[a-z] | 匹配小写 a-z 任何一个字母 |
[A-Z] | 匹配大写 A-Z 任何一个字母 |
[]:原子表,里面写的东西算包含(可选的意思),加上^表示 除了
【】内不解析字符含义,点只代表点的意思。也不需要转义
原子组 ( ):
- 如果一次要匹配多个元子,可以通过元子组完成
- 原子组与原子表的差别在于原子组一次匹配多个元子,而原子表则是匹配任意一个字符
- 元字符组用
()
包裹,表示一个整体,就类似组的概念
|:表示或,配合原子组()一起使用
引用分组:
\n
在匹配时引用原子组,例如\1,\2。
下面使用原子组匹配 h1
标签,如果想匹配 h2
只需要把前面原子组改为 h2
即可。
const hd = `<h1>houdunren.com</h1>`;
console.log(/<(h1)>.+<\/\1>/.test(hd)); //true
$n
指在替换时使用匹配的组数据。
let hd = `<h1>houdunren</h1><span>后盾人</span><h2>hdcms</h2>
`;let reg = /<(h[1-6])>([\s\S]*)<\/\1>/gi;
console.log(hd.replace(reg, `<p>$2</p>`));
多个正则校验思路:
将正则规则写成数组,利用数组的every方法进行子项的正则的test方法,返回布尔值。
<body>
<input type="text" name="password" />
</body>
<script>
let input = document.querySelector(`[name="password"]`);
input.addEventListener("keyup", e => {const value = e.target.value.trim();const regs = [/^[a-zA-Z0-9]{5,10}$/, /[A-Z]/];let state = regs.every(v => v.test(value));console.log(state ? "正确!" : "密码必须包含大写字母并在5~10位之间");
});
</script>
正则方法:
exec;检索字符串,还不如用match
reg.exec(str)
let s = 'yuu'如果不加g,和match一样,拿出来的是详细信息 加了g以后,要配合while循环才能拿到下一个匹配字符 这里没写while循环,所以结果一样let reg = /u/gconsole.log('reg.exec(s)', reg.exec(s)) ['u', index: 1, input: 'yuu', groups: undefined]
test:检索返回布尔值
reg.test(str)
关于正则的字符串方法:
search:返回索引
寻找符合要求的字符串,返回索引,没有的话为-1,还不如include方法,括号里面可以写正则
match:匹配出符合要求的字符串
如果正则语法加了全局修饰符g,则匹配出来的不会有详细信息,返回是一个数组。想要有详细信息使用matchall
let hd = "houdunren";
let res = hd.match(/u/);
console.log(res); 一段数组,详细信息['u', index: 2, input: 'houdunren', groups: undefined]
console.log(res[0]); //匹配的结果
console.log(res[index]); //出现的位置let hd = "houdunren";加全局g let res = hd.match(/u/g);console.log(res);['u', 'u']
matchAll:检索出符合要求的迭代对象,配合全局g使用
全局匹配:返回的是一个正则迭代数组集,里面是每个详细信息。可以遍历。
let str = "houdunren";let reg = /[a-z]/ig;let arr = []for (const iterator of str.matchAll(reg)) {// console.log(iterator);arr.push(iterator[0])}console.log('arr', arr)
split:分割,括号里面可以写正则
let str = "2023/02-12";
console.log(str.split(/-|\//));
replace:替换方法,常用于字符串的增删改查,配合正则*******
常用的字符串替换。对字符串进行增删改查优先考虑这个替换方法,找到替换元素直接改成想要的格式。
简单用法:
let str = "2023/02-12";str = str.replace(/\/|-/g, "")console.log('str', str)在字符串的后面加东西let hd = "(010)99999999 (020)8888888";hd = hd.replace(/\)/g, ')-')console.log('hd', hd) (010)-99999999 (020)-8888888在字符串的后面加东西let hd = "(010)99999999 (020)8888888";使用替换特殊变量名,$&代表匹配出的字符本身,下面有介绍hd = hd.replace(/\)/g, '$&-')console.log('hd', hd) 结果一样
复杂用法:
1:替换字符串可以插入下面的特殊变量名:不需要回调函数的形式
变量 | 说明 |
---|---|
$$ | 插入一个 "$"。 |
$& | 插入匹配的子串。有用,可以直接拿到正则匹配的字符串 |
$` | 插入当前匹配的子串左边的内容。 |
$' | 插入当前匹配的子串右边的内容。 |
$n | 假如第一个参数是 RegExp 对象,并且 n 是个小于 100 的非负整数,那么插入第 n 个括号匹配的字符串。提示:索引是从 1 开始,配和正则的原子组使用 |
在后盾人前后添加三个=let hd = "=后盾人=";
console.log(hd.replace(/后盾人/g, "$`$`$&$'$'"));
把电话号用 - 连接let hd = "(010)99999999 (020)8888888";
console.log(hd.replace(/\((\d{3,4})\)(\d{7,8})/g, "$1-$2"));
把所有教育汉字加上链接 https://www.houdunren.com<body>在线教育是一种高效的学习方式,教育是一生的事业
</body>
<script>const body = document.body;body.innerHTML = body.innerHTML.replace(/教育/g,`<a href="https://www.houdunren.com">$&</a>`);
</script>
2:replace方法的第二个参数可以是一个回调函数
replace 支持回调函数操作,用于处理复杂的替换逻辑
回调函数接受的参数。参数顺序排名
- 匹配到的字符
- 原子组的排序(有几个就排到几个,比如两个,参数用到就占有两个,p1,p2)
- 位置,很少用到
- 原字符串
变量名 | 代表的值 |
---|---|
match | 匹配的子串。(对应于上述的$&。) |
p1,p2, ... | 假如 replace()方法的第一个参数是一个 RegExp 对象,则代表第 n 个括号匹配的字符串。(对应于上述的$1,$2 等。)例如,如果是用 /(\a+)(\b+)/ 这个来匹配,p1 就是匹配的 \a+ ,p2 就是匹配的 \b+ 。 |
offset | 匹配到的子字符串在原字符串中的偏移量。(比如,如果原字符串是 'abcd' ,匹配到的子字符串是 'bc' ,那么这个参数将会是 1) |
string | 被匹配的原字符串。 |
NamedCaptureGroup | 命名捕获组匹配的对象 |
用途:操作html中的文本标签内容
替换页面的内容标签
const reg = /<(h[1-6])>(.*?)<\/\1>/g;const body = document.body.innerHTML;const html = body.replace(reg, function (str, tag, content) {console.log('str', str) //匹配出的字符串console.log('tag', tag) //标签 其实是第一个原子组console.log('content', content) //内容 其实是第二个原子组return `<p>${content}</p>`; 模板字符串的写法});document.body.innerHTML = html;完整用法let content = document.querySelector(".content");let reg = /<(h[1-6])>([\s\S]*?)<\/\1>/gi;content.innerHTML = content.innerHTML.replace(reg,(search, //匹配到的字符p1, //第一个原子组p2, //第二个原子组index, //索引位置source //原字符) => {return `<${p1} class="hot">${p2}</${p1}>`;});
断言匹配:
为正则的前后加上判断条件,相当于弄了一层约束,更精准
Promise:
关于promise的内容单独放了一篇文章
Promise的异步同步问题_成为前端大牛的博客-CSDN博客_promise异步转同步