1,递归
递归函数:一个函数在内部可以调用其本身
function func() {
func()
}
func()
递归容易发生栈溢出错误(stack overflow),以上是一个典型的栈溢出,所以我们必须加退出条件
return
var num = 1
function func() {
console.log(`打印${num}次`)
if (num === 10) {
return
}
num++
func()
}
func()
递归实例:
- 1, 利用递归求 1 ~ n 的阶乘
function func(n) {
// 1 * 2 * 3 * ...n
if (n === 1) return 1;
return n * func(n - 1)
}
func(5) // 120
- 2, // 斐波那契数列(兔子序列):前两项的和等于第三项的值 表现: 1、1、2、3、5、8、13、21、34...
// 用户输入一个数字 n, 求出这个数字对应的兔子序列值
function fb (n) {
if (n === 1 || n === 2) return 1
return fb(n - 1) + fb(n - 2)
}
fb(9) // 34
- 3, 根据 id 返回对应的数据对象
const arr = [
{
id: 1,
name: 'Jerry',
friends: [
{
id: 11,
name: 'Lise'
},
{
id: 12,
name: 'Tom'
}
]
},
{
id: 2,
name: 'xiaowang'
}
];
const arr = [
{
id: 1,
name: 'Jerry',
friends: [
{
id: 11,
name: 'Lise'
},
{
id: 12,
name: 'Tom'
}
]
},
{
id: 2,
name: 'xiaowang'
}
];
function getId(data, id) {
var o = {}
data.forEach(function (value) {
if (value.id === id) {
o = value
return value
} else if (value.friends?.length > 0) {
o = getId(value.friends, id)
}
})
return o
}
console.log(getId(arr, 12)) // {id: 12, name: 'Tom'}
或者
function getId(arr, id) {
let queue = [];
arr.forEach(item => {
queue.push(item)
})
while(queue.length > 0) {
const value = queue.shift();
if(value.id === id) return value;
if(value.friends && value.friends.length > 0) {
value.friends.forEach(item => queue.push(item));
}
}
}
console.log(getId(arr, 12)) // {id: 12, name: 'Tom'}
2,深浅拷贝
- 1,浅拷贝只是拷贝一层,更深层对象级别的只拷贝引用
- 2,深拷贝拷贝多层,每一级别的数据都会拷贝
浅拷贝
const obj = {
name: 'Jerry',
age: 18,
friends: {
name: 'Lise'
}
};
var o = {}
for (var i in obj) { // i 属性名,obj[i] 属性值
o[i] = obj[i]
}
或
Object.assign(o, obj) // ES6新增的方法可以实现浅拷贝
o.friends.name = 'Tom'
console.log(o)
console.log(obj)
深拷贝
const obj = {
name: 'Jerry',
age: 18,
friends: {
name: 'Lise'
},
colors: ['red', 'green', 'blue']
};
var o = {}
// 封装函数
function deepCopy(newObj, oldObj) {
for(var i in oldObj) {
// 判断属性值是简单数据类型还是复杂数据类型
// 1,获取属性值 oldObj[i]
const item = oldObj[i]
// 2, 判断这个值是否是数组
if (item instanceof Array) {
newObj[i] = []
deepCopy(newObj[i], item)
} else if (item instanceof Object) {
// 3,判断这个值是否是对象
newObj[i] = {}
deepCopy(newObj[i], item)
} else {
// 4,属于基本数据类型
newObj[i] = item
}
}
}
deepCopy(o, obj)
3,正则表达式
正则表达式:用于匹配字符串中字符组合的模式,在JS中,正则表达式也是对象。
通常用于检测、替换那些符合某个模式的文本,例如验证表单:用户名表单只能输入英文字母、数字或者下划线。
还常用于过滤页面内容中的一些敏感词(替换),或者从字符串中获取我们想要的特定部分等
3.1,创建正则表达式
- 创建正则表达式:
- 1, 利用
RegExp
对象来创建
const rg = new RegExp(/表达式/)
- 2, 利用字面量创建正则表达式
const rg = /表达式/
- 1, 利用
- 测试正则表达式
test
test()正则对象的方法,用于检测字符串是否符合该规范,该对象会返回true
或false
const rg = /123/
rg.test(123) // true
rg.test(456) // false
- 正则的组成
一个正则可以由简单的字符组成,比如/abc/,也可以是简单和特殊字符的组合,比如/ab*c/,特殊字符有叫元字符,在正则中具有特殊意义的专用符号,比如: ^、$、+等
特殊符号可以参考:MDN正则表达式
正则测试工具:https://tool.oschina.net/regex
3.2,正则中的特殊字符
- 3.2.1 边界符
正则中的边界符(位置符)用来提示字符串所处的位置,主要有两个:^、$- ^ 匹配行首的文本
- $ 匹配行尾的文本
const rg = /abc/ // /abc/表示只要包含有abc这个字符串返回的都是true
console.log(rg.test('abc')) // true
console.log(rg.test('abcd')) // true
console.log(rg.test('aabc')) // true
const reg = /^abc/ // 表示必须以abc开头的
console.log(reg.test('abc')) // true
console.log(reg.test('abcd')) // true
console.log(reg.test('aabc')) // false
console.log(reg.test('abdc')) // false
const reg1 = /^abc$/ // 精确匹配
console.log(reg1.test('abc')) // true
console.log(reg1.test('abcd')) // false
console.log(reg1.test('aabc')) // false
- 3.2.2 字符类:[]
表示有一系列字符可供选择,只要匹配其中一个就可以了
const reg = /[abc]/ // 表示只要包含有a 或 有b 或 有c,都返回true
console.log(reg.test('alia')) // true
const reg1 = /^[abc]$/ // 表示只有是a 或 b 或 c,才返回true
console.log(reg1.test('alia')) // false
console.log(reg1.test('a')) // true
console.log(reg1.test('b')) // true
console.log(reg1.test('bc')) // false
console.log(reg1.test('c')) // true
console.log(reg1.test('cc')) // false
console.log(reg1.test('abc')) // false
- 3.3.3 [-]方括号内 范围符 -
const reg = /^[a-z]$/ // 26个英文字母任何一个字母返回true
console.log(reg.test('alia')) // false
console.log(reg.test('a')) // true
console.log(reg.test('A')) // false
- 3.3.4 字符组合
// 字符组合
const reg1 = /^[a-zA-Z]$/ // // 26个英文字母(大小写都可以) 任何 一个字母返回true
console.log(reg1.test('alia')) // false
console.log(reg1.test('a')) // true
console.log(reg1.test('A')) // true
// 比如:reg = /^[a-zA-Z0-9_-]$/
- 3.4.5 []方括号内 表示取反
const reg = /^[^abc]$/
console.log(reg.test('a')) // false
- 3.4.6 量词符
用来设定某个模式出现的次数
量词 | 说明 |
---|---|
* | 重复0次或更多次 |
+ | 重复1次或更多次 |
? | 重复0次或1次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
// * >= 0
const reg = /^a*$/
console.log(reg.test('')) // true
console.log(reg.test('a')) // true
console.log(reg.test('b')) // false
console.log(reg.test('aaa')) // true
// + >= 1
const reg1 = /^a+$/
console.log(reg1.test('')) // false
console.log(reg1.test('a')) // true
console.log(reg1.test('b')) // false
console.log(reg1.test('aaa')) // true
// ? 1 || 0
const reg2 = /^a?$/
console.log(reg2.test('')) // true
console.log(reg2.test('a')) // true
console.log(reg2.test('b')) // false
console.log(reg2.test('aaa')) // false
// {3} 重复3次
const reg3 = /^a{3}$/
console.log(reg3.test('')) // false
console.log(reg3.test('a')) // false
console.log(reg3.test('b')) // false
console.log(reg3.test('aaa')) // true
// {3,} >= 3
const reg4 = /^a{3,}$/
console.log(reg4.test('')) // false
console.log(reg4.test('a')) // false
console.log(reg4.test('b')) // false
console.log(reg4.test('aaa')) // true
console.log(reg4.test('aaaaa')) // true
console.log(reg4.test('aaabc')) // false
console.log('-----------')
// {3,8} >= 3 && <= 8
const reg5 = /^a{3,8}$/
console.log(reg5.test('')) // false
console.log(reg5.test('a')) // false
console.log(reg5.test('b')) // false
console.log(reg5.test('aaa')) // true
console.log(reg5.test('aaaaa')) // true
console.log(reg5.test('aaabc')) // false
console.log(reg5.test('aaaaaaaa')) // true
- 3.4.7
// 量词是设定某个模式出现的次数
var reg = /^[a-zA-Z0-9_-]$/ // 这个模式用户只能输入英文字母 数字 下划线 短横线但是有边界符和[] 这就限定了只能多选1
console.log(reg.test('a')) // true
console.log(reg.test('ab')) // false
console.log(reg.test(1)) // true
console.log(reg.test('11')) // false
console.log(reg.test('aa')) // false
4, 正则案例
1, 用户名验证,如果用户名输入合法,提示信息为:用户名合法,颜色改为绿色,如果不合法,则后面提示:用户名不符合规范,改色改为红色
const name = document.querySelector('.name');
const span = document.querySelector('span');
var reg = /^[a-zA-Z0-9_-]{6,16}$/
name.onblur = function () {
if (reg.test(this.value)) {
span.className = 'green'
span.innerHTML = '用户名合法'
} else {
span.className = 'red'
span.innerHTML = '用户名不符合规范'
}
}
5, 括号总结
- 1,量词符大括号,表示重复次数
- 2,字符集合中括号,匹配方括号中的任意字符
- 3,小括号,表示优先级
// 中括号[],字符集合,匹配方括号中的任意字符
const reg = /^[abc]$/ // a || b || c都可以
// 大括号{},量词符,表示重复次数
const reg1 = /^[abc]{3}$/
console.log(reg1.test('aaa')) // true
console.log(reg1.test('abcabcabc')) // false
const reg2 = /^abc{3}$/ // 它只是让c重复3次 abccc
console.log(reg2.test('aaa')) // false
console.log(reg2.test('abcabcabc')) // false
console.log(reg2.test('bbb')) // false
console.log(reg2.test('ccc')) // false
console.log(reg2.test('abccc')) // true
console.log(reg2.test('aabccc')) // false
// 小括号 表示优先级
const reg3 = /^(abc){3}$/ // 表示让 abc重复3次
console.log(reg3.test('aaa')) // false
console.log(reg3.test('abcabcabc')) // true
console.log(reg3.test('abccc')) // false
6,可以在线测试自己写的正则对不对(https://c.runoob.com/front-end/854/)
也会有一些常用的正则:
7,预定义类
指的是某些常见模式的简写方式
预定义类 | 说明 |
---|---|
\d | 匹配0-9之间的任一数字, 相当于[0-9] |
\D | 匹配所有0-9以外的字符, 相当于[^0-9] |
\w | 匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_] |
\W | 除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_] |
\s | 匹配空格(包括换行符、制表符、空格符),相当于[\t\r\n\v\f] |
\S | 匹配非空格的字符,相当于[^\t\r\n\v\f] |
实例:
// 座机号码验证:全国座机号码,两种格式:010-12345678 或者 0530-1234567
// const reg = /^\d{3}-\d{8}|\d{4}-\d{7}$/ // 正则里的 或 用 | 表示
// 简写
const reg = /^\d{3,4}-\d{7,8}$/
console.log(reg.test('魑魅魍魉')) // false
console.log(reg.test('3829889')) // false
console.log(reg.test('3829-889')) // false
console.log(reg.test('022-31231321')) // true
8, replace 替换
replace()方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则
// 语法
str.replace(/str/, replacement)
// 第一个参数:被替换的字符串 或者 正则
// 第二个参数:替换为的字符串
// 返回值是一个替换完的新字符串
const str = 'JerryLise'
const newStr = str.replace('Jerry', 'xiaowang')
const newStr = str.replace(/Jerry/, 'xiaowang')
console.log(newStr) // xiaowangLise
实例:
const text = document.querySelector('textarea')
const btn = document.querySelector('button')
const div = document.querySelector('div')
btn.onclick = function () {
div.innerHTML = text.value.replace(/小猫咪/, '**')
}
以上代码replace只能替换第一个满足条件的字符串,后面的就不再替换了,那么我们可以用正则表达式参数
9,正则表达式参数
/表达式/[switch]
// switch也称修饰符,按照什么样的模式来匹配,有三种值:
// 1,g: 全局匹配
// 2,i:忽略大小写
// 3,gi:全局匹配 + 忽略大小写
以上实例:
div.innerHTML = text.value.replace(/小猫咪|超/g, '**')