阅读 688

【前端体系】正则在开发中的应用场景可不只是规则校验

前言

对于正则相信大家都不陌生,可能有的小伙伴已经学过不至一遍了,是不是学了就忘系列🙃。对于正则其实用的最多的就是规则校验,很多人都是抱着这样的心态的:正则不就是写一些规则校验嘛,网上很多人都写好了。需要时候再拿过来用就行了。我也是这么想的🤣, 所以本文重点是讲正则在我们实际编码中的帮助。

在最近开发的时候应用上了正则帮我省下了不少事,需求是这样的:

在当前列表里,点击编辑条目的时候我可以获取到当前的登录身份:是总经理还是财务、普通经理等等、可以拿到当前条目的状态是:1待签订 2已签订 3待审核 4条目已废除,其中的一项

我的需求是:不管是总经理还是财务的身份,我都可以编辑条目,但是如果是财务编辑过这项条目我需要执行一个方法记录当前条目被财务编辑过(如果条目状态为4则不需要),如果是总经理则不需要, 如果财务编辑了状态为4的条目我需要执行一个方法,其余的1-3状态执行另一个方法

身份: 'CEO' | 'CFO' | ....
状态: 1待签订   2已签订  3待审核  4条目已废除

其他身份都是执行一样的逻辑,需要对 CEO和CFO这两状态做特殊处理
如果是财务编辑了这条目:
	我需要做的判断: 
	1、只要是财务,不管是哪个状态都执行一个方法A(和总经理不是同一个方法)
	2、如果财务编辑的是状态1-3的条目我需要执行一个方法B
	3、如果财务编辑的是状态为4条目我需要执行一个方法C
如果是总经理编辑了这条目:
	1、只要是总经理,不管那种状态都执行这个方法D(和财务不是同一个方法)
	
function A
function B
function C
function D
复制代码

毫无疑问上面这个需求肯定不能单纯的条件判断, 得用点奇淫技巧🤔, 解决方案我写在了最后面,感兴趣的小伙伴继续往下看噢(是不是很有小心思呢😉)

在线卑微,如果觉得这篇文章对你有帮助的话欢迎大家点个赞👻

目录👇

正则的核心

正则表达式:用于匹配规律规则的表达式,正则表达式最初是科学家对人类神经系统的工作原理的早期研究,现在在编程语言中有广泛的应用。正则表通常被用来检索、替换那些符合某个模式(规则)的文本。正则表达式是对字符串操作的一种逻辑公式(一套校验规则),就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来对字符串的进行过滤逻辑。

在开始前先了解下正则的核心我们再来学习它,对于这些核心点下面的文章中都会详细解答,请各位小伙伴先记住

三大作用

  1. 给定的字符串是否符合正则表达式的过滤逻辑(匹配)
  2. 可以通过正则表达式,从字符串中获取我们想要的特定部分(提取)
  3. 强大的字符串替换能力(替换)

三大元素

想要玩好正则重要的就是需要记住正则的三大元素:元字符、修饰符、量词。这三点也是正则组成最重要的部分,虽然我也是很不喜欢记一些东西的,但是这个就像是最基础的语法一样,你连这些都不知道的话怎么去写出一套好的正则判断(理解你刚复制过来的正则校验)呢。

三大核心点

一套正则校验规则最重要的部分也就是三大核心点:定锚点、去噪点、取数据,这三点是整个正则处理过程中的灵魂,它贯穿整个正则撰写过程。

源数据:
<a href="http://www.beige.wolrd/blog" class="demo" title="正则核心点应用举例">正则表达式</a>
需求:提取链接和标题,还有a标签的文字
复制代码

看到这个源数据和需求,我们必须定位好锚点,主要有:

  • <a 必须是a标签
  • href=" 和 " // href=""的内容得到链接
  • title=" " // title=""的内容得到标题
  • > 和 </a> // >和</a>的内容得到标签文字

然后,其他的都是噪点,使用.*?替代,需要提取的数据部分使用括号捕获,得到分组数据,因此得到正则:

<a href="(.*?)".*?title="(.*?)">(.*?)</a>
复制代码

取数据:我们通过将表达式分组捕获的数据通过反向引用就能取出来

两大特性

正则就像我们人一样有两个"不好"的特性:即懒惰、又贪婪。

懒惰性:天生自带,如果不加全局匹配(g),只会匹配第一趟符合的结果就不向后匹配了

贪婪性:后天形成,当正则表达式中包含能接受重复的限定符(如:+、?、*)时,就会产生贪婪匹配的效果

举个栗子🌰来讲吧

在讲解前先了解一下lastIndex这个属性,它表示正则下一次匹配的位置,在没有全局修饰(g)的情况下,它始终是0,如果加了g它记录每次匹配结果字符的位置,标示开始下一次匹配的字符位置。

let str = '1212 3434 5656';
let reg = /\d\d\d\d/;

console.log(reg.exec(str)); // 不加g(全局匹配)lastIndex始终是从0开始匹配
console.log(reg.exec(str)); // 不加g(全局匹配)lastIndex始终是从0开始匹配
console.log(reg.lastIndex); // 一个整数,标示开始下一次匹配的字符位置


reg =  /\d\d\d\d/g; // => 加g之后会记录每次匹配的字符位置, lastIndex为下一次匹配的字符位置
console.log(reg.exec(str)) // 1212
console.log(reg.lastIndex) // 0
console.log(reg.exec(str)) // 3434
console.log(reg.lastIndex) // 4
复制代码

上面例子中在加了g修饰符之后就解决了正则的懒惰性

贪婪性:上面说了如果正则表达式包含限定字符之后才会出现,具体还是看例子

let reg = /\d+/;
let str = '2018 2019 2020';
reg.exec(str) 
复制代码

上面的答案大家应该都知道,2018啊,为什么是2018? \d+表示:数字出现一次或多次,20不就符合了嘛?

就是因为限定符的出现所以正则开启了贪婪模式,在找到符合的时候他还会向下一个查找发现还符合,继续向下找,找到右边的空格之后发现不符合了就不找了。

通过加个可解决正则的贪婪性

reg = /\d+?/; // => 用?限定了前面的表达式结果只能出现0次或一次,在有些语言中是用这个方式: *?
复制代码

正则的组成

元字符

表示拥有特殊含义的字符,单个或者元字符组合在一起代表特殊的含义

注1:

/e\b/.test('The javaScript') => 匹配前面的单词边界
结果true

// => The javaScript 中e就是区分这是两单词的边界, 所以上面的就能匹配到e,因为是e这个单词当做边界将这个字符串区分开的,不然后计算机也不知道他是两单词

/\be/.test('The javaScript') => 匹配后面的单词边界
结果false

// => 这里的前面的单词边界是T、J并没有e

这里需要注意的是:'The javaScript'这个字符串中,最前面的T和t也是属于单词边界
复制代码

修饰符

放在正则表达式的外面作为修饰

量词

限定字符的个量数

方括号

方括号表示一个范围,也称为字符簇

找规律

元字符:对于\w、\d、\s、\b, 大写就是相反的意思

方括号:是定义匹配的字符范围,比如 [a-zA-Z0-9],表示字符文本要匹配英文字符和数字

花括弧:n{x, y}一般用来表示匹配的长度

正则的转义需要注意的点

在我们编写正则表达式的时候如果我们需要匹配正则中的特殊字符时需要进行转义。例:

我们就单纯的想匹配:\ + 字母d

let reg1 = /^\\d$/g;
    reg2 = new RegExp('^\\d$', 'g');
    

console.log(reg1.test('^\\d$')); // true

console.log(reg2.test('^\\d$')); // ?

reg2 = new RegExp('^\\\d$', 'g');
console.log(reg2.test('^\\d$')); // ?
复制代码

先自己做下再看答案



----------------------------------------------- 我是分割线 ----------------------------------------



上面哪题我猜百分80的小伙伴都错了🙃

两个都输出false, 我们先来分析下转移字符,\在js中表示转移字符,//表示正则,在正则中也有转移字符

上图可以了解到在js中\+字母也是有特殊意义的,有些表示别的字符,有些还是表示原来的字符

reg2 = new RegExp('^\\\\d$', 'g');
复制代码

new RegExp这种方式创建正则有个很容易被忽略点

  • 第一个\在js中也有特殊含义, \d -> d
  • 第二个\是将\在js中的特殊含义转义成没有意义 -> \d

坑的来了🙂

reg2 = new RegExp('^\\\\d$', 'g');
// => 前面两个\\
// -> 第一个在js中本来是表示特殊含义的: \d -> d
// -> 第二个\将前面的在\js中转换成没有意义的\ -> \(js中转移后的\)d
因为new RegExp里面写的是正则。在正则中\d表示数字

但是第三个\并不是将 \d转换成正则中没有含义的\d, 因为这个\d是js转换后的\d, 只不过是因为new RegExp里面写的都是正则表达式所以我当成了\d(表示数字),当我想要让他在正则中表示特殊含义我需要再转换一次
// -> 第三个\将 `\d(js中的\)`  变成正则中有意义的\ -> \d(表示数字)

复制代码
  • 第三个\将 \d(js中的\) 变成正则中有意义的\ -> \d(表示数字)
  • 第四个\\d(正则中的\): 表示数字转义成没有意义的 '\d'

看图

环视(断言)

环视,在不同的地方又称之为零宽断言,简称断言。 用一句通俗的话解释: 环视,就是先从全局环顾一遍正则,(然后断定结果) 再做进一步匹配处理。 断言,就是先从全局环顾一遍正则,然后断定结果,再做进一步匹配处理。

两个虽然字面不一样,意思却是同一个,都是做全局观望,再做进一步处理。

  • 先行断言:x(?=y) -> 只有后面有y的x才匹配
  • 先行否定断言:x(?!y) -> 只有后面没有y的x才匹配
  • 后行断言:(?<=y)x -> 只有前面有y的x匹配才匹配
  • 后行否定断言: (? 只有前面没有y的x才匹配

先行断言/先行否定断言

/\d+(?=%)/.exec('100% of US presidents have been male'); // ["100"]
/\d+(?!%)/.exec('that’s all 64% of them');                 // ["6"]
复制代码

第一个正则:匹配数字后面有%号, 第二个正则:匹配数字后面没有%号。

后行断言/后行否定断言

/(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill');  // ["100"]
/(?<!\$)\d+/.exec('it’s is worth about €90');                // ["90"]
复制代码

第一个正则:匹配数字前面,第二个正则:匹配数字前面没有符, 第二个正则:匹配数字**前面**没有符。

结论: 这两个刚好是反着来的

  • 先行断言/先行否定断言:是对前面的表达式进行限定,写在表达式后面,表达式后面需要有指定内容
    • /\d+(?=%)/ => 对\d表达式匹配的字符串进行限定, 写在\d后面, 表示数字后面需要有%
  • 后行断言/后行否定断言:是对后面的表达式进行限定,写在表达式前面,表达式前面需要有指定内容
    • /(?<!\$)\d+/ => 对\d表达式匹配的字符串进行限定, 写在\d前面, 表示数字前面需要有$

捕获(分组)和引用

在正则表达式出现的小括号就叫捕获或者分组,小括号包着的表达式就叫子表达

正则内的引用

在正则语法中(在//内),在捕获的后面,用\1来引用前面的捕获。用\2表示第二个捕获的内容…

let str='1122 3434 5678 9090 1516';

// 要求: 匹配连续的4个数字
console.log(/\d\d\d\d/.exec(str));
console.log(/\d{4}/.exec(str));
console.log(/[0-9]{4}/.exec(str));
// => 上面柜种方式都能匹配到1122

// 要求:匹配连续的4个数字。要求第1个数字和第3个数字相同
console.log(/(\d)\d\1\d/.exec(str)); // 3434
// => 通过对第一个数的捕获,第三个数引用第一个数, 第一个数是啥我就是啥
// => 9090 1516也符合要求因懒惰性没有继续向下匹配,加g可解决

// 要求:匹配连续的个数字。要求第1个数字和第3个数字相同,并且第2个数字和第个4数字相同
console.log(/(\d)(\d)\1\2/.exec(str));

// 要求:匹配连续的4个数字。要求第1数字和第2个数字相同,第3个和第个4相同
console.log(/(\d)\1(\d)\2/.exec(str));
复制代码

正则外的引用

在正则语法外(如replace时),用$1来引用前面的捕获。

let str = 'abcd123';
let ret = str.replace(/([a-z])/g, '$1$1');
console.log(ret); // aabbccdd123
复制代码

表示捕获的内容左侧的内容,用` 表示捕获的内容左侧的内容,用 ' 表示捕获的内容右侧的内容

// 替换yck 为 y-[y-c-k]-k
let str = 'yck';
let ret = str.replace(/(c)/, "-[$`-$1-$']")
console.log(ret);
复制代码

如果只想捕获不引用,用(?:)表示只捕获不去引用,在数组中也就不会出现捕获的内容

let str = 'Bei ge';
console.log(/([A-z])/.exec(str));
/**
 * 0: "B"
 * 1: "B" // 第一个括号捕获的内容
 * groups: undefined
 * index: 0
 * input: "Bei ge"
 * length: 2
 */
console.log(/(?:[A-z])/.exec(str));
/**
 * 0: "B"
 * groups: undefined
 * index: 0
 * input: "Bei ge"
 * length: 2
 */
复制代码

核心点: 捕获和引用就很好的运用了正则的三大作用,通过编写正则匹配符合规则校验的字符,我们通过反向引用提取出捕获的内容,然后通过替换的方法将原字符串进行替换

做过的正则面试题

题目

用正则表达式来将字符串
"I? love ?? the ?great ? ?wall in ?beijing"
更改为:"I love the Great Wall in Beijing"复制代码

主要是为了解决编码的问题导致的问题,规律:

  • 乱码只有特殊字符'?';
  • 如果乱码的末尾是'?'则它的下一位字母肯定是大写;
  • 如果?前面有字母那它就是单纯的问号

使用环视加捕获的方式:

/**
 * 
 * 前面没有字母的?:(?<![A-z])\?
 * ?后面有字母 & 字母前面有?:\?(?=[a-z])((?<=\?)[a-z])
 * 空格后面还有空格的换成一个空格:'(?<=) '
 * 
 */
let reg = /((?<![A-z])\?(?![a-z])|\?(?=[a-z])((?<=\?)[a-z]))/g;
let ret = originalStr.replace(reg, (_, $1, $2) => {
  return $2 ? $2.toUpperCase() : '';
})
console.log(ret);
复制代码

上面这道题我当时用的不是这种解法,这里为了用上断言所以用了这种方式还是比较麻烦的,还有更简单的方法欢迎大佬评论区留言😀

能使用正则表达式的方法

正则对象

  • exec
  • test

exec返回值:如果成功返回数组,失败返回null

let str = '1212 3434 5656';
let reg = /(\d)\d\d\d/g;
console.log(reg.exec(str));  //  ["1212", "1", index: 0, input: "1212 3434 5656", groups: undefined]

/*
 * 0: "1212"
 * 1: "1"
 * groups: undefined
 * index: 0
 * input: "1212 3434 5656"
 * length: 1
 */
复制代码

解释下上面数组每个属性的意思

  • 以数字为索引的属性表示正则捕获的结果

    1、0标识一定是最大的正则捕获的结果

    2、1至后面的索引分别是分组捕获的结果,如果有两个捕获就会有2:第二个分组捕获的结果

  • groups: 命名捕获组

  • index: 当前字符在原始字符的索引位置

  • input: 原始字符串

test返回值: 如果成功返回true,失败返回false

let str = '1212 4';
let reg = /\d\d\d\d/;

console.log(reg.test(str)); // true
console.log(reg.test(str)); // false
复制代码

字符串对象

  • match
  • matchAll
  • search
  • replace

match返回值:加g会加符合正则的所有结果,不加g返回第一个匹配及捕获数组,外加index、groups、input这三个附属性

let str = '1212 4567';
let reg = /\d\d\d\d/;

console.log(str.match(reg)); // ["1212", index: 0, input: "1212 4567", groups: undefined]

reg = /\d\d\d\d/g;
console.log(str.match(reg)); // ["1212", "4567"]
复制代码

matchAll返回值:一个包含所有匹配正则表达式的结果及分组捕获组的迭代器

const regexp = /t(e)(st(\d?))/g;
const str = 'test1test2';

const array = [...str.matchAll(regexp)];

console.log(array[0]); 
// ["test1", "e", "st1", "1", index: 0, input: "test1test2", groups: undefined]

console.log(array[1]); 
// ["test2", "e", "st2", "2", index: 5, input: "test1test2", groups: undefined]
复制代码

search返回值:类似indexOf不过它可以放入一个正则,返回正则匹配到该字符串的首次匹配项的索引

let str = 'the Nine';
let reg = /Nine/g
console.log(str.search(reg)); // 4
console.log(str[str.search(reg)]); // N
复制代码

replace返回值:返回由替换值替换后的字符串,

function replacer(match, p1, p2, p3) {
  /**
   * p1: 第一个分组捕获的结果
   * p2: 第二个分组捕获的结果
   * p3: 第三个分组捕获的结果
   */
  console.log(`${match}---- ${p1}----${p2}----${p3}`);
  return [p1, p2, p3].join(' - ');
}
let newString = 'abc12345#$*%'.replace(/([^\d]*)(\d*)([^\w]*)/, replacer);
console.log(newString);  // => abc - 12345 - #$*%
复制代码

这个方法算是应用场景最多一个方法了。

交换两个字符在字符串中的位置

var reg = /(\w+)\s(\w+)/;
var str = "序号 2";
var newstr = str.replace(re, "$2, $1");
// Smith, John
console.log(newstr);
复制代码

收,对于方法讲解就到这了,文章的目的不是对于API的讲解,这段是为了帮小伙伴过一下API的用法(其实是我忘了😝)

使用场景

时间格式化字符串

对于时间格式化大多还是用正则,这里推荐一个比较好用时间格式化的方法Date.toLocaleDateString

let time = '2020-9-10 13:23:13'; 

String.prototype.formatTime = function formatTime(template) {
  // 如果没有满足10位补零
  let arr = this.match(/\d+/g).map(item => {
    return item.length < 2 ? '0' + item : item;
  });
  
  // 如果用户未设定模板,用默认的模板替换
  template = template || '{0}年{1}月{2}日 {3}时{4}分{5}秒';
  return template.replace(/\{(\d+)\}/g, (_, group) => {
    return arr[group] || "00";
  });
};
console.log(time.formatTime());
复制代码

字符串中出现最多的字符,出现的次数

对象键名标识的方式

String.prototype.repeatQuery = function () {
  let originalStr = this,
    map = new Map(),
    max = 0,
    char = '';
  let strList = originalStr.split('');

strList.reduce((map, item) => map.has(item) ? map.set(item, map.get(item) + 1) : map.set(item, 1), map)
  for (let [key, val] of map.entries()) {
    if (val > max) {
      max = val;
      char = key;
    } else if (val === max) {
      char += `, ${key}`;
    }
  }
  return `${char}出现最多,出现了${max}次`
}
复制代码

正则的方式

let str = 'The Bei ge gg';
// options: 可以配置不计算的字符
String.prototype.repeatQuery = function (options = []) {
  let exceptReg = new RegExp(`[${options.join('')}]`, 'g')
  let newStr = this.replace(exceptReg, '');
  
  let arr = [...new Set(newStr.split(''))],
    max = 0,
    char = '';
  for (let i = 0; i < arr.length; i++) {
    let reg = new RegExp(arr[i], 'g');
    let repeatNum = newStr.match(reg).length
    if (repeatNum > max) {
      max = repeatNum;
      char = arr[i];
    } else if (repeatNum === max) { // 出现字符次数相同的情况
      char += `,${arr[i]}`
    }
  }
  return `${char}出现最多,出现了${max}次`
}

// 配置不匹配的项有 空格、'、"
console.log(str.repeatQuery(['\'', '\"', ' ']));;
复制代码

实现千分符

例子用到的值

let num1 = 1234567894532;
let num2 = 123435.4542;
复制代码

方法加截取实现

function numFormatter(num) {
  num = num.toString().split("."); // 分隔小数点
  let arr = num[0].split("").reverse(); // 转换成字符数组并且倒序排列
  let res = [];
  arr.forEach((item, i) => {
    if (i % 3 === 0 && i !== 0) {
      res.push(',');
    }
    res.push(item);
  })
  res.reverse(); // 再次倒序成为正确的顺序
    
  // 如果有小数点拼接成小数点
  res = num[1] ? res.join('').concat(`.${num[1]}`) : res.join(''); 
  return res;
}

console.log(numFormatter(num1)); // 1,234,567,894,532
console.log(numFormatter(num2)); // 123435.4,542
复制代码

正则的方式

function numFormatter(num) {
  return num.toString().replace(/\d{1,3}(?=(\d{3})+$)/g, val => val + ',')
}
console.log(numFormatter(num1));
console.log(numFormatter(num2));
console.log(numFormatter(num1)); // 1,234,567,894,532
console.log(numFormatter(num2)); // 123435.4,542
复制代码

获取url中的传参

例子用到的值

let str = 'http://www.beige.world/blog/?name=beige&public=前端自学驿站#auto';
复制代码

方法加截取实现

function queryUrlParams(url) {
  let result = new Object(),
      index = url.indexOf('?'),
      HASH = null;

  if(index != -1) {
    let params = url.substr(index + 1);
        
    // 处理hash
    if (params.indexOf('#')) {
      HASH = params.split('#')[1]
      params = params.split('#')[0];
    }

    let arr = params.split('&');
    arr.forEach(c => {
      result[c.split('=')[0]] = (c.split('=')[1]);
    })

    HASH && (result['HASH'] = HASH)
    return result
    
  }

  return result;
}
复制代码

正则的方式

function queryUrlParams(originalStr) {
  // 哈希值值的处理
  let obj = {}; 
  originalStr.replace(/#([^?=#&]+)/g, (_, group) => obj['HASH'] = group); 

  // 问号传参信息的处理 
  originalStr.replace(/([^?#=&]+)=([^?#=&]+)/g, (_, $1, $2) => {
    obj[$1] = $2;
  });
  return obj;
}
console.log(queryUrlParams(str));
{
    HASH: "auto"
	name: "beige"
	public: "前端自学驿站"
}
复制代码

真实项目遇到的问题解决方案

把前面的需求拷贝下来,分析一下。

需求是这样的:

在当前合同条目里,点击编辑条目的时候我可以获取到当前的登录身份:是总经理还是财务、普通经理等等、可以拿到这条合同的状态是:1待签订 2已签订 3待审核 4条目已废除,其中的一项

我的需求是:不管是总经理还是财务的身份,我都可以编辑条目,但是如果是财务编辑过这项条目我需要执行一个方法记录当前条目被财务编辑过(如果状态为4则不需要),如果是总经理则不需要, 如果财务编辑的了状态为4的条目我需要执行一个方法,其余的1-3状态执行同一个方法

身份: 'CEO' | 'CFO' | ....
状态: 1待签订   2已签订  3待审核  4条目已废除

其他身份都是执行一样的逻辑,需要对 CEO和CFO这两状态做特殊处理
如果是财务编辑了这条目:
	我需要做的判断: 
	1、只要是财务,不管是哪个状态都执行一个方法A(和总经理不是同一个方法)
	2、如果财务编辑的是状态1-3的条目我需要执行一个方法B
	3、如果财务编辑的是状态为4条目我需要执行一个方法C
如果是总经理编辑了这条目:
	1、只要是总经理,不管那种状态都执行这个方法D(和财务不是同一个方法)
	
function A
function B
function C
function D
复制代码

这里毋庸置疑肯定是不能单单用if条件判断的,不然代码太过冗长了。我最开始能想到最优的办法是这样的

const handles = ()=>{
    const functionA = ()=>{/*一大段处理A逻辑的代码*/}
    const functionC = ()=>{/*一大段处理B逻辑的代码*/}
    return new Map([
      [{identity:'CFO',status:1},functionA],
      [{identity:'CFO',status:2},functionA],
      [{identity:'CFO',status:3},functionA],
      [{identity:'CFO',status:4},functionC],
    ])
}
  
 
let params = '合同id';
// 将逻辑函数缓存下来
const functionB = ()=>{/*一大段处理B逻辑的代码*/}
const functionD = ()=>{/*一大段处理D逻辑的代码*/}
const onButtonClick = (identity,status)=>{
let action = [...handles()].filter(([key,value])=>(key.identity == identity && key.status == status))
    action.forEach(([key, value]) => {value.call(this, params)});
    
    let statusList = [1, 2, 3, 4];
    // 单独处理一下身份是财务, 无论哪个状态的情况
    if (identity === 'CFO') {
      if (statusList.includes(status)) {
        functionB()
      } 
    } else if (identity === 'CEO') {
      if (statusList.includes(status)) {
        functionD()
      } 
    }
  }
复制代码

上面的方法我是利用了Map数据结构可以用对象作为键值对,我将需要判断的身份和状态放了进去,当点击的时候通过对每项的键存储的身份和状态进行判断,对应的操作方法,不过对于CEO每个状态需要做处理。

下面是用正则处理的方式

// => 利用正则的键可以是任务数据类型,我们将正则条件作为键名
  const handles = ()=>{
    const functionA = ()=>{console.log('一大段处理A逻辑的代码');}
    const functionB = ()=>{console.log('一大段处理B逻辑的代码');}
    const functionC = ()=>{console.log('一大段处理C逻辑的代码');}
    const functionD = ()=>{console.log('一大段处理D逻辑的代码')}
    return new Map([
      [/^CFO_[1-3]$/, functionA],
      [/^CFO_.*$/, functionB],
      [/^CFO_4$/, functionC],
      [/^CEO.*$/, functionD],
    ])
  }
  
  // 利用数组的循环每次符合正则条件的逻辑都会被执行,
  // 那就可以同时执行公共逻辑和单独逻辑,
  
  let params = '条目id';
  const onButtonClick = (identity,status)=>{
    let action = [...handles()].filter(([key,value])=>(key.test(`${identity}_${status}`)))
    action.forEach(([key,value])=>value.call(this, params))
  }
复制代码

正则不止是做一些规则校验,在我们实际编码中能使用正则的场景还有很多,只要大家不拘束于它只是规则校验你能玩出很多花样😜

写在最后

对于【前端体系】这系列的文章我是抱着很认真,很想写好的心态的,但毕竟我还是前端小白&写作新人,如果文章中有那块写的不太好或有问题欢迎大家指出,我也会在后面的文章不停修改。也希望自己进步的同时能跟你们一起成长。喜欢我文章的朋友们也可以关注一下

我会很感激第一批关注我的人。此时,年轻的我和你,轻装上阵;而后,富裕的你和我,满载而归。

系列文章

【前端体系】从一道面试题谈谈对EventLoop的理解 (更新了四道进阶题的解析)

【前端体系】从地基开始打造一座万丈高楼

参考文章

前端正则最全知识汇总

深入理解正则表达式高级教程