- ES6主要是为了解决ES5的先天不足,比如JavaScript里并没有类的概念,但是目前浏览器的JavaScript是ES5版本,大多数高版本的浏览器也支持ES6,不过只显示了ES6的部分特性和功能。
变量声明 let const
-
var:
- 可以重复声明
- 存在变量提升(即将声明提升到最前面)
- 不存在块级作用域
-
let:
- 不可以重复声明
- 可以变量提升
- 存在块级作用域
-
const:
- 不可以重复声明
- 块级作用域
- 声明时必须赋值
- 声明后不可以进行修改
- const声明的数组内容可以被修改,所以常规使用const进行数组变量的声明
- 注意点 :
暂时性死区
在代码块内,使用let、const命令声明变量之前,该变量都是不可用的。这在语法上,称为暂时性死区。使用var声明的变量不存在暂时性死区
解构赋值
ES6允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
数组的解构赋值:数组解构赋值中,变量的值取决于后面的数组的位置,因为它是有序的
let [a,b,c] = [1,2,3];
console.log(a,b,c);
对象的解构赋值
let{name,age} = { a:'xjj',b:'18' };
console.log(name,age);
字符串解构赋值
const [a, b, c, d, e] = "hello"
console.log(a,b,c,d,e);
模板字符串
ES6中允许使用反引号 ` 来创建字符串,此种方法创建的字符串里面可以包含由美元符号加花括号包裹的变量${vraible}。
JavaScript写法
var name = 'xjj',age = 18;
let desc = name +'is'+ age +'year old!';
console.log(desc);
模板字符串写法
var name = 'xjj',age = 18;
let desc = `${name} is ${age} year old!`;
console.log(desc);
箭头函数
ES6允许使用「箭头」(=>)定义函数
var name = "吴彦祖"
//箭头函数 : 将普通函数的`function`关键字删掉, 在小括弧与大括弧中间加上1个箭头`=>`,用法与普通函数一样
let getName2 = () => {
console.log(this.name);
}
// 等同于
//常规声明
function getName() {
console.log(this.name);
}
getName();//吴彦祖
getName2();//吴彦祖
// 没有参数
let fun1 = () => {
console.log(111);
};
// 只有一个参数,可以省去参数括号
let fun2 = name => {
console.log(`Hello ${name} !`)
};
// 有多个参数
let fun3 = (val1, val2, val3) => {
return [val1, val2, val3];
};
// 总结箭头函数语法:
// 1.采用箭头=>来定义函数。
// 2.函数的参数放在=>前面的括号中,函数体跟在=>后的花括号中。
// 3.如果箭头函数没有参数,直接写一个空括号即可。
// 4.如果箭头函数的参数只有一个,也可以省去包裹参数的括号。
// 5.如果箭头函数有多个参数,将参数依次用逗号(,)分隔,包裹在括号中即可。
箭头函数的特点:
- 箭头函数语法更加简洁、清晰,不需要function关键字来创建函数
- 箭头函数没有 prototype (原型),所以箭头函数本身没有this
- 箭头函数的this在定义的时候继承于外层第一个普通函数的this。
- 如果箭头函数外层没有普通函数,严格模式和非严格模式下它的this指向window(全局对象)。
- call | apply | bind 不能改变箭头函数中this的指向
- 不可以当作构造函数,也就是说,不可以对箭头函数使用
new
命令,否则会抛出一个错误。 - 不可以使用
arguments
对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
面试题扩展:
面试题一 : new操作符都做了写什么
- 创建了一个新的空对象
- 将构造函数的作用域赋给新对象(也就是将对象的proto属性指向构造函数的prototype属性)
- 指向构造函数中的代码,构造函数中的this指向该对象(也就是为这个对象添加属性和方法)
- 返回新的对象
面试题二 : this的指向有哪几种
- 默认绑定:全局环境中,this默认绑定到window。
- 隐式绑定:一般地,被直接对象所包含的函数调用时,也称为方法调用,this隐式绑定到该直接对象。
- .隐式丢失:隐式丢失是指被隐式绑定的函数丢失绑定对象,从而默认绑定到window。显式绑定:通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定。
- new绑定:如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。对于this绑定来说,称为new绑定
面试题三 : bind、apply、call的区别
- apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。
- call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法。
- bind除了返回是函数以外,它的参数和call一样。
扩展运算符
数组的扩展运算符
— 将一个数组转为用逗号分隔的参数序列。
// 基本用法
const TFboys = ['王源','易烊千玺','王俊凯'];
console.log(...TFboys);
// 用法一:合并数组
const kuaizi = ['肖央','王太利'];
const fenghuang = ['曾毅','玲花'];
// ES5的写法
const zuixuan = kuaizi.concat(fenghuang);
// ES6的写法
const zuixuan = […fenghuang,…kuaizi];//使用扩展运算符
// 用法二:克隆数组
const arr1 = ['苹果','香蕉','水蜜桃'];
const arr2 = […arr1];//使用...进行clone
// 用法三:将伪数组转化成为真正的数组
const divs = document.querySelectorAll('div');
const divarr = [..divs];//已经转化为了真正的数组
对象的扩展运算符
—用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中
// 基本用法
let a = { a: 1, b: 2 };
let b = { ...a }; // { a: 1, b: 2 }
// 对象的扩展运算符等同于使用Object.assign()方法。
let aClone = { ...a };
// 等同于
let aClone = Object.assign({}, a);
// 注意: Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。扩展运算符对对象实例的拷贝属于浅拷贝
Promise对象
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。ES6 将其写进了语言标准,统一了用法,原生提供了Promise
Promise的基本概念:
- Promise是ES6出来的一个构造函数,可以new一个Promise实例
- 函数参数有两个参数 resolve(成功之后的回调函数) 、reject(失败之后的回调函数)
- Promise一旦声明就会立刻执行一次里面的代码
- 用来解决回调地狱
promise的三种状态:
- pending(进行中)、 当promise实例化出时状态就为pending
- fulfilled(已成功) 调用resolve就是已成功状态,也就是说你写 resolve() 除了可以调用你传入的回调函数,还可以把状态改为 已成功fulfilled
- rejected(已失败) 调用reject就是已失败状态也就是说你写 reject() 除了调用你传入的回调函数,还把状态改成了 已失败(rejected)
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
Promise的基本使用
//概念看的再多,也不一定能知道如何使用,接下来通过代码来看看Promise的使用和好处
//实例化promise
const promise = new Promise(function(resolve, reject) {
let a = 1
if (a == 1) {
//成功
resolve(a)
} else {
//失败
reject(error)
}
})
案例:
// 回调地狱
const fs = require('fs')
//先读取出a的内容,再读取b的内容,再读取c的内容
fs.readFile('./files/a.txt', (error, data) => {
console.log(data.toString());
fs.readFile('./files/b.txt', (error, data) => {
console.log(data.toString());
fs.readFile('./files/c.txt', (error, data) => {
console.log(data.toString());
})
})
})
//以上代码会导致出现回调地狱,而promise就是用来解决这种“回调地狱”的
解决方案:
//封装一下,将文件路径当做参数传递
function readPromise(path) {
let p = new Promise((reslove, reject) => {
//读取文件
fs.readFile(`./files/${path}.txt`, (error, data) => {
if (error) {
reject(error)
} else {
reslove(data.toString())
}
})
})
return p
}
//调用readPromise方法,依次读取。.then中,返回一个promise实例,可以继续使用下一个 .then来处理
readPromise('a').then((res) => {
console.log(res);
return readPromise('b')
})
.then( res => {
console.log(res);
return readPromise('c')
} )
.then( res => {
console.log(res);
} )
Promise的方法
-
.then()
: Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。采用链式的then,可以指定一组按照次序调用的回调函数。 -
.catch()
: 用于指定发生错误时的回调函数,如果状态变为resolved,则会调用then方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误。另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获 -
.
finally
: 不管promise
最后的状态,在执行完then
或catch
指定的回调函数以后,都会执行finally
方法指定的回调函数。 -
.all()
: 用于将多个 Promise 实例,包装成一个新的 Promise 实例。(接收到的数组的顺序就是响应回来的顺序)// Promise.all()方法接受一个数组作为参数 let p1 = new Promise((resolve, reject) => { resolve('成功了') }) let p2 = new Promise((resolve, reject) => { resolve('success') }) let p3 = Promse.reject('失败') Promise.all([p1,p3,p2]).then((result) => { console.log(result) }).catch((error) => { console.log(error) // 失败了,打出 '失败' })
-
.rece()
: 将多个实例包装成一个新实例,返回全部实例状态优先变更后的结果(先响应先返回)// Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。 let p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') },1000) }) let p2 = new Promise((resolve, reject) => { setTimeout(() => { reject('failed') }, 500) }) Promise.race([p1, p2]).then((result) => { console.log(result) }).catch((error) => { console.log(error) // 打开的是 'failed' })
promise的一些问题
- 一旦执行,无法中途取消,链式调用多个then中间不能随便跳出来
- 错误无法在外部被捕捉到,只能在内部进行预判处理,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
- Promise内部如何执行,监测起来很难,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
Module - 模块
在ES6标准中,JavaScript原生支持module了。这种将JS代码分割成不同功能的小块进行模块化的概念是在一些三方规范中流行起来的,比如CommonJS和AMD模式。
- ES6模块主要有两个功能:export和import
// export导出: 用于对外输出本模块(一个文件可以理解为一个模块)变量的接口
// import导入: 用于在一个模块中加载另一个含有export接口的模块。
// 将不同功能的代码分别写在不同文件中,各模块只需导出公共接口部分,然后通过模块的导入的方式可以在其他地方使用
// 暴露函数 --- test.js
let myName="laowang";
let myAge=90;
export function getName (){
return "我是"+myName+"!今年"+myAge+"岁了"
}
// 引用函数
import { getName } from "./test.js"
console.log(getName())
export与export default:
- export与export default均可用于导出常量、函数、文件、模块等
- 你可以在其它文件或模块中通过import+(常量 | 函数 | 文件 | 模块)名的方式,将其导入,以便能够对其进行使用
- 在一个文件或模块中,export、import可以有多个,export default仅有一个
- 通过export方式导出,在导入时要加{ },export default为模块指定默认输出,不需要知道所要加载模块的变量名。
async 函数
-
async
函数是Generator
函数的语法糖。使用 关键字async
来表示,在函数内部使用await
来表示异步。 -
对于
Generator
,async
的区别在哪里- 内置执行器。Generator 函数的执行必须依靠执行器,而
Aysnc
函数自带执行器,调用方式跟普通函数的调用一样 - 更好的语义。
async
和await
相较于*
和yield
更加语义化 - 更广的适用性。
co
模块约定,yield
命令后面只能是 Thunk 函数或 Promise对象。而async
函数的await
命令后面则可以是 Promise 或者 原始类型的值(Number,string,boolean,但这时等同于同步操作) - 返回值是 Promise。
async
函数返回值是 Promise 对象,比 Generator 函数返回的 Iterator 对象方便,可以直接使用then()
方法进行调用
- 内置执行器。Generator 函数的执行必须依靠执行器,而
基本用法:
// 基本用法
async function foo() {
let result = await "b";
return result;
}
foo().then((value) => console.log(value)); // b
-
优点
- 它做到了真正的串行的同步写法,代码阅读相对容易
- 对于条件语句和其他流程语句比较友好,可以直接写到判断条件里面
- 处理复杂流程时,在代码清晰度方面有优势
-
缺点
- 无法处理promise返回的reject对象,要借助try…catch…
- 用 await 可能会导致性能问题,因为 await 会阻塞代码,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性。
- try…catch…内部的变量无法传递给下一个try…catch…,Promise和then/catch内部定义的变量,能通过then链条的参数传递到下一个then/catch,但是async/await的try内部的变量,如果用let和const定义则无法传递到下一个try…catch…,只能在外层作用域先定义好。
Map和Set
Map对象
- Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
- Map结构提供了“值-值”的对应,是更完善的Hash结构实现。Map可以作为构造函数。
// 声明
const user = new Map();
// 添加成员
user.set(name, 'xjj');
user.set(title, '帅过吴彦祖');
// 成员总数
map.size // 2
// 读取成员
user.get(name); // true
// 检查成员
user.has(title); // true
// 删除成员
user.delete(name); // true
// 清除所有成员
user.clear();
map.size // 0
-
Map的属性
size
返回实例的成员总数。constructor
构造函数,默认就是Map
函数。
-
Map的方法
-
操作方法
- set(key, val) :
设置键名
key对应的键值为
value`,然后返回整个 Map 结构 - get(key): 读取
key
对应的键值,如果找不到key
,返回undefined
。 - has(key): 返回一个布尔值,表示某个键是否在当前 Map 对象之中。
- delete(key): 删除某个键,返回
true
。如果删除失败,返回false
。 - clear(): 清除所有成员,没有返回值。
- set(key, val) :
-
遍历方法
- Map.prototype.keys() :**返回键名的遍历器。
- Map.prototype.values(): 返回键值的遍历器。
- Map.prototype.entries(): 返回所有成员的遍历器。
- Map.prototype.forEach(): 遍历 Map 的所有成员。
-
Set对象
- Set本质也是一个构造函数,因此在使用时需要new,同时Set可以接收一个数组(或者具有 iterable 接口的其他数据结构)作为参数用来初始化Set
- Set中的值可以是任意类型的,但必须不能重复
- Set的最大特点就是,里面的值都是唯一的,因此可以用来进行数组去重使用
- Set也可以为字符串去重
- Set 是可遍历的
// 数组去重
const set = new Set([1, 2, 3, 4, 4]);
console.log([...set]) // [1, 2, 3, 4]
// 字符串去重
let str = 'abcabcaabbcc'
let set = new Set(str)
str = [...set].join('')
console.log(str);//abc
-
Set的属性
size
返回实例的成员总数。constructor
构造函数,默认就是Set
函数。
-
Set的方法
-
操作方法
- add(value): 添加某个值,返回 Set 结构本身。
- delete(value): 删除某个值,返回一个布尔值,表示删除是否成功。
- has(value): 返回一个布尔值,表示该值是否为
Set
的成员。 - clear(): 清除所有成员,没有返回值。
-
遍历方法
- Set.prototype.keys(): 返回键名的遍历器
- Set.prototype.values(): 返回键值的遍历器
- Set.prototype.entries(): 返回键值对的遍历器
- Set.prototype.forEach(): 使用回调函数遍历每个成员
-
class语法
<!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>class语法</title>
</head>
<body>
<!--
除了JS语言之外, 其他编程语言 以JAVA为首, 都采用的是 class 语法来管理对象相关的操作
JS独创了原型设计
呼声: 从其他语言中转型到JS语言的程序员, 希望JS能引入class语法来管理对象
JS 在ES6的新特性中增加了 class 语法
-->
<script>
// 复习: JS的原型写法
function Test(a, b) {
// let this = {}
this.a = a
this.b = b
// this.__proto__ = Test.prototype
// return this
}
//
Object.defineProperty(Test.prototype, 'show', {
value: function () {
console.log('我是show')
},
})
var a = new Test(10, 20)
console.log(a)
///////////////////////////////////////
// class语法
// class中: 同时封装了构造函数 和 原型的方法
class Demo {
// 固定名称的属性: constructor
// new运算符, new Demo() 就会触发此固定名称的方法
constructor(a, b) {
this.a = a
this.b = b
}
// class语法中: 相关的原型方法直接写到此处即可
// 省略 function 前缀
show() {
console.log('我是show')
}
// 从其他语言转入的人: 都排斥 构造函数.prototype 的语法
talk() {}
ab() {}
cc() {}
}
// 可以认为: class语法 就是 原型写法的 语法糖
var d = new Demo(10, 20)
console.log(d)
// d.show: d中没有show, 则到原型中查找使用
d.show()
</script>
</body>
</html>
<!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>
</head>
<body>
<script>
// 静态属性: 就是对象的属性
// 遗憾: JAVA中没有下方这种语法
// var b = { name: 'MIKE' }
// console.log(b.name)
// console.log(b)
class a {
static name = 'MIKE'
static age = 29
}
// 相当于: JS的 {name:'MIKE', age:29}
// 但是JAVA的class语法, 需要用 static 标注
console.dir(a)
console.log(a.name)
console.log(a.age)
</script>
</body>
</html>
<!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>继承</title>
</head>
<body>
<!--
面向对象开发的 三大特征: 封装 继承 多态
- 封装: 用{}把很多代码括起来,形成一个整体
- 继承: 在JS中就是原型链特征, 自己没有到原型中找
-->
<script>
var a = { name: 'MIKE', age: 33 }
console.log(a)
// 替换对象类型的原型
// set:设置 prototype:原型 of: ...的
Object.setPrototypeOf(a, Array.prototype)
// 把 a 的原型, 换成 Array.prototype
// 换原型的作用:
function sum() {
console.log('arguments:', arguments)
// 想用数组的高阶函数: reduce 计算
// arguments:的原型是 Object, 是伪数组, 没有高阶函数
// 原型换成数组的
Object.setPrototypeOf(arguments, Array.prototype)
var t = arguments.reduce((total, value) => total + value, 0)
console.log(t)
}
sum(12, 3, 23, 34, 45, 45, 6, 765)
</script>
<script>
// 创建对象类型时, 指定其原型
// create: 创建
// 一个普通对象在创建时, 指定其原型是谁
// new Array(); new Date(); -- 单一,专业
// create: 万能方式
var p = Object.create(Array.prototype)
var p = Object.create(Date.prototype)
p.age = 11
p.sex = 33
console.log(p)
</script>
<script>
// JAVA中: 类也可以指定 父类(原型)
class Father {
constructor() {
this.a = 3
}
show() {}
}
// extends: 继承 Father 类, Demo创建出的对象的原型, 就是Father创建的对象
// 方法在原型中存储, 属性会存到顶层对象里, 即 show 和 a 的差异
class Demo extends Father {}
// 继承: 父的东西 都会 传递给子使用
var d = new Demo()
console.log(d)
</script>
</body>
</html>
<!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>
</head>
<body>
<!--
面向对象的三大特征
1. 封装: {}把代码括起来, 形成一个整体 -- 例如 函数的{},对象的{}
2. 继承: 原型链特征 -- 自己没有的属性, 到原型__proto__中查找
-- 其他语言中: 爸爸的资源给了儿子用
3. 多态: 多种状态 -- 同样的方法 在 父子中触发, 效果不同,多种状态
-->
<script>
// 重写: 继承-子可以拥有父类所有的方法和属性, 但是子可以声明 同名的方法和属性, 来代替从父类继承的
class Father {
show() {
console.log('我是父类')
}
}
class Son extends Father {
// 重写: 父类中的方法, 在子类中声明同名方法, 则使用时优先用自身的重写方法
show() {
// 关键词: super -- 指定调用父类的方法
// 与this关键词对应, this代表当前对象
super.show() //打印出 : 我是父类
console.log('我是子类')
}
}
var s = new Son()
console.log(s)
s.show()
</script>
</body>
</html>
正则表达式的元字符
字符 | 含义 |
---|---|
`` | 依照下列规则匹配:在非特殊字符之前的反斜杠表示下一个字符是特殊字符,不能按照字面理解。例如,前面没有 “” 的 “b” 通常匹配小写字母 “b”,即字符会被作为字面理解,无论它出现在哪里。但如果前面加了 “”,它将不再匹配任何字符,而是表示一个字符边界。在特殊字符之前的反斜杠表示下一个字符不是特殊字符,应该按照字面理解。详情请参阅下文中的 “转义(Escaping)” 部分。如果你想将字符串传递给 RegExp 构造函数,不要忘记在字符串字面量中反斜杠是转义字符。所以为了在模式中添加一个反斜杠,你需要在字符串字面量中转义它。/[a-z]\s/i 和 new RegExp("[a-z]\s", "i") 创建了相同的正则表达式:一个用于搜索后面紧跟着空白字符(\s 可看后文)并且在 a-z 范围内的任意字符的表达式。为了通过字符串字面量给 RegExp 构造函数创建包含反斜杠的表达式,你需要在字符串级别和正则表达式级别都对它进行转义。例如 /[a-z]:\/i 和 new RegExp("[a-z]:\\","i") 会创建相同的表达式,即匹配类似 “C:” 字符串。 |
^ | 匹配输入的开始。如果多行标志被设置为 true,那么也匹配换行符后紧跟的位置。例如,/^A/ 并不会匹配 “an A” 中的 ‘A’,但是会匹配 “An E” 中的 ‘A’。当 ‘^ ’ 作为第一个字符出现在一个字符集合模式时,它将会有不同的含义。反向字符集合 一节有详细介绍和示例。 |
$ | 匹配输入的结束。如果多行标志被设置为 true,那么也匹配换行符前的位置。例如,/t$/ 并不会匹配 “eater” 中的 ‘t’,但是会匹配 “eat” 中的 ‘t’。 |
* | 匹配前一个表达式 0 次或多次。等价于 {0,} 。例如,/bo*/ 会匹配 “A ghost boooooed” 中的 ‘booooo’ 和 “A bird warbled” 中的 ‘b’,但是在 “A goat grunted” 中不会匹配任何内容。 |
+ | 匹配前面一个表达式 1 次或者多次。等价于 {1,} 。例如,/a+/ 会匹配 “candy” 中的 ‘a’ 和 “caaaaaaandy” 中所有的 ‘a’,但是在 “cndy” 中不会匹配任何内容。 |
? | 匹配前面一个表达式 0 次或者 1 次。等价于 {0,1} 。例如,/e?le?/ 匹配 “angel” 中的 ‘el’、“angle” 中的 ‘le’ 以及 "oslo’ 中的 ‘l’。如果紧跟在任何量词 、 +、? 或 {} 的后面,将会使量词变为非贪婪*(匹配尽量少的字符),和缺省使用的贪婪模式(匹配尽可能多的字符)正好相反。例如,对 “123abc” 使用 /\d+/ 将会匹配 “123”,而使用 /\d+?/ 则只会匹配到 “1”。还用于先行断言中,如本表的 x(?=y) 和 x(?!y) 条目所述。 |
. | (小数点)默认匹配除换行符之外的任何单个字符。例如,/.n/ 将会匹配 “nay, an apple is on the tree” 中的 ‘an’ 和 ‘on’,但是不会匹配 ‘nay’。如果 s (“dotAll”) 标志位被设为 true,它也会匹配换行符。 |
(x) | 像下面的例子展示的那样,它会匹配 ‘x’ 并且记住匹配项。其中括号被称为捕获括号。模式 /(foo) (bar) \1 \2/ 中的 ‘(foo) ’ 和 ‘(bar) ’ 匹配并记住字符串 “foo bar foo bar” 中前两个单词。模式中的 \1 和 \2 表示第一个和第二个被捕获括号匹配的子字符串,即 foo 和 bar ,匹配了原字符串中的后两个单词。注意 \1 、\2 、…、\n 是用在正则表达式的匹配环节,详情可以参阅后文的 \n 条目。而在正则表达式的替换环节,则要使用像 $1 、$2 、…、$n 这样的语法,例如,'bar foo'.replace(/(...) (...)/, '$2 $1') 。$& 表示整个用于匹配的原字符串。 |
(?:x) | 匹配 ‘x’ 但是不记住匹配项。这种括号叫作非捕获括号,使得你能够定义与正则表达式运算符一起使用的子表达式。看看这个例子 /(?:foo){1,2}/ 。如果表达式是 /foo{1,2}/ ,{1,2} 将只应用于 ‘foo’ 的最后一个字符 ‘o’。如果使用非捕获括号,则 {1,2} 会应用于整个 ‘foo’ 单词。更多信息,可以参阅下文的 Using parentheses 条目. |
x(?=y) | 匹配’x’仅仅当’x’后面跟着’y’.这种叫做先行断言。例如,/Jack(?=Sprat)/会匹配到’Jack’仅当它后面跟着’Sprat’。/Jack(?=Sprat |
(?<=y) x | 匹配’x’仅当’x’前面是’y’.这种叫做后行断言。例如,/(?<=Jack)Sprat/会匹配到’ Sprat ‘仅仅当它前面是’ Jack '。/(?<=Jack |
x(?!y) | 仅仅当’x’后面不跟着’y’时匹配’x’,这被称为正向否定查找。例如,仅仅当这个数字后面没有跟小数点的时候,/\d+(?!.)/ 匹配一个数字。正则表达式/\d+(?!.)/.exec(“3.141”)匹配‘141’而不是‘3.141’ |
(?<!*y*)*x* | 仅仅当’x’前面不是’y’时匹配’x’,这被称为反向否定查找。例如, 仅仅当这个数字前面没有负号的时候,/(?<!-)\d+/ 匹配一个数字。 /(?<!-)\d+/.exec('3') 匹配到 “3”. /(?<!-)\d+/.exec('-3') 因为这个数字前有负号,所以没有匹配到。 |
[`x | y`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions#special-or) |
{n} | n 是一个正整数,匹配了前面一个字符刚好出现了 n 次。 比如, /a{2}/ 不会匹配“candy”中的’a’,但是会匹配“caandy”中所有的 a,以及“caaandy”中的前两个’a’。 |
{n,} | n是一个正整数,匹配前一个字符至少出现了n次。例如, /a{2,}/ 匹配 “aa”, “aaaa” 和 “aaaaa” 但是不匹配 “a”。 |
{n,m} | n 和 m 都是整数。匹配前面的字符至少n次,最多m次。如果 n 或者 m 的值是0, 这个值被忽略。例如,/a{1, 3}/ 并不匹配“cndy”中的任意字符,匹配“candy”中的a,匹配“caandy”中的前两个a,也匹配“caaaaaaandy”中的前三个a。注意,当匹配”caaaaaaandy“时,匹配的值是“aaa”,即使原始的字符串中有更多的a。 |
[xyz] | 一个字符集合。匹配方括号中的任意字符,包括转义序列。你可以使用破折号(-)来指定一个字符范围。对于点(.)和星号(*)这样的特殊符号在一个字符集中没有特殊的意义。他们不必进行转义,不过转义也是起作用的。 例如,[abcd] 和[a-d]是一样的。他们都匹配"brisket"中的‘b’,也都匹配“city”中的‘c’。/[a-z.]+/ 和/[\w.]+/与字符串“test.i.ng”匹配。 |
[^xyz] | 一个反向字符集。也就是说, 它匹配任何没有包含在方括号中的字符。你可以使用破折号(-)来指定一个字符范围。任何普通字符在这里都是起作用的。例如,abc 和 a-c 是一样的。他们匹配"brisket"中的‘r’,也匹配“chop”中的‘h’。 |
[\b] | 匹配一个退格(U+0008)。(不要和\b混淆了。) |
\b | 匹配一个词的边界。一个词的边界就是一个词不被另外一个“字”字符跟随的位置或者前面跟其他“字”字符的位置,例如在字母和空格之间。注意,匹配中不包括匹配的字边界。换句话说,一个匹配的词的边界的内容的长度是0。(不要和[\b]混淆了)使用"moon"举例: /\bm/匹配“moon”中的‘m’; /oo\b/并不匹配"moon"中的’oo’,因为’oo’被一个“字”字符’n’紧跟着。 /oon\b/匹配"moon"中的’oon’,因为’oon’是这个字符串的结束部分。这样他没有被一个“字”字符紧跟着。 /\w\b\w/将不能匹配任何字符串,因为在一个单词中间的字符永远也不可能同时满足没有“字”字符跟随和有“字”字符跟随两种情况。注意: JavaScript的正则表达式引擎将特定的字符集定义为“字”字符。不在该集合中的任何字符都被认为是一个断词。这组字符相当有限:它只包括大写和小写的罗马字母,十进制数字和下划线字符。不幸的是,重要的字符,例如“é”或“ü”,被视为断词。 |
\B | 匹配一个非单词边界。匹配如下几种情况:字符串第一个字符为非“字”字符字符串最后一个字符为非“字”字符两个单词字符之间两个非单词字符之间空字符串例如,/\B…/匹配"noonday"中的’oo’, 而/y\B…/匹配"possibly yesterday"中的’yes‘ |
\c*X* | 当X是处于A到Z之间的字符的时候,匹配字符串中的一个控制符。例如,/\cM/ 匹配字符串中的 control-M (U+000D)。 |
\d | 匹配一个数字。``等价于[0-9] 。例如, /\d/ 或者 /[0-9]/ 匹配"B2 is the suite number."中的’2’。 |
\D | 匹配一个非数字字符。``等价于[^0-9] 。例如, /\D/ 或者 /[^0-9]/ 匹配"B2 is the suite number."中的’B’ 。 |
\f | 匹配一个换页符 (U+000C)。 |
\n | 匹配一个换行符 (U+000A)。 |
\r | 匹配一个回车符 (U+000D)。 |
\s | 匹配一个空白字符,包括空格、制表符、换页符和换行符。等价于[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。例如, /\s\w*/ 匹配"foo bar.“中的’ bar’。经测试,\s不匹配”\u180e",在当前版本Chrome(v80.0.3987.122)和Firefox(76.0.1)控制台输入/\s/.test(“\u180e”)均返回false。 |
\S | 匹配一个非空白字符。等价于 [^ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff] 。例如,/\S\w*/ 匹配"foo bar."中的’foo’。 |
\t | 匹配一个水平制表符 (U+0009)。 |
\v | 匹配一个垂直制表符 (U+000B)。 |
\w | 匹配一个单字字符(字母、数字或者下划线)。等价于 [A-Za-z0-9_] 。例如, /\w/ 匹配 “apple,” 中的 ‘a’,"$5.28,"中的 ‘5’ 和 “3D.” 中的 ‘3’。 |
\W | 匹配一个非单字字符。等价于 [^A-Za-z0-9_] 。例如, /\W/ 或者 /[^A-Za-z0-9_]/ 匹配 “50%.” 中的 ‘%’。 |
*n* | 在正则表达式中,它返回最后的第n个子捕获匹配的子字符串(捕获的数目以左括号计数)。比如 /apple(,)\sorange\1/ 匹配"apple, orange, cherry, peach."中的’apple, orange,’ 。 |
\0 | 匹配 NULL(U+0000)字符, 不要在这后面跟其它小数,因为 \0<digits> 是一个八进制转义序列。 |
\xhh | 匹配一个两位十六进制数(\x00-\xFF)表示的字符。 |
\uhhhh | 匹配一个四位十六进制数表示的 UTF-16 代码单元。 |
\u{hhhh}或\u{hhhhh} | (仅当设置了u标志时)匹配一个十六进制数表示的 Unicode 字符。 |
测试方式
123456789
ABCDEFG
abcdefg
你好啊 亮亮
vscode 用 ctrl+F 可以弹出搜索框, 支持 正则匹配搜索
\d: 代表任意数字
[x-x]: 代表字符集合, 例如[1-9] [a-z] [A-Z]
<!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>正则表达式</title>
</head>
<body>
<!-- 正则表达式: Regular Expression 简称 RegExp -->
<!-- 非JS专有的一种 通用的字符串格式模糊匹配的方式 -->
<!-- 官方提供了一套文档, 提供了一些元字符 具有特殊含义 -->
<script>
// 正则表达式 在 JS中如何使用??
var words = 'ABCD JQK 123 456 亮亮今天没上课'
// 希望找出所有的 数字
// 正则的字符: \d 代表任意数字
// 正则表达式 在JS中使用, 必须转为 正则对象才可以
// 正则对象的转换方式分两种: 字面量 和 构造方式
var reg = /\d/ // 通过 // 字符, 来包裹 正则字符
console.log(reg) // 美化后的样子
console.dir(reg) // 本质的样子: 对象类型
// match: 字符串的match方法, 匹配
// 从字符串中 匹配出 符合 正则对象 要求的字符
// 正则表达式的修饰符
// g: global 全局匹配 -- 匹配出所有符合条件的
reg = /\d/g // /正则/修饰符
var r = words.match(reg)
console.log(r)
</script>
</body>
</html>
修饰符
<!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>正则修饰符</title>
</head>
<body>
<script>
//
var words = 'abcd ABCD 1234 亮亮不在家'
// 所有的字母
// g: 全部,所有
// i: ignore 忽略大小写
var reg = /[a-z]/gi
// 构造方式: 效果同上
// 参数1: 正则表达式 参数2: 修饰符
reg = new RegExp('[a-z]', 'ig')
// 坑: 匹配所有数字
// : 字符串的转义符. '\d' 转义成 'd'
// 此处必须写 '\d' , \ 转义符把 \ 变为普通\
reg = new RegExp('\d', 'g')
console.log(words.match(reg))
</script>
</body>
</html>
正则替换
<!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>正则替换</title>
</head>
<body>
<script>
var words = 'xx今天不在家, xx也没上课'
// 把 xx 换成 亮亮
// replace(要替换的值, 换成什么)
console.log(words.replace(/xx/g, '亮亮'))
// 利用正则的修饰符 g: 实现全局替换
var phone = '13899878456'
// 转化成 xxx-xxxx-xxxx 的格式
// {n}: 代表前方的元素 重复 n 个
var reg = /(\d{3})(\d{4})(\d{4})/
// $n: 第n个小括号捕捉的值, 小括号称为 捕获组
var r = phone.replace(reg, '$1-$2-$3')
// 把手机号变为: xxx****xxxx 中间4位隐藏
var r = phone.replace(reg, '$1****$3')
console.log(r)
</script>
</body>
</html>
正则验证
<!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>正则验证</title>
</head>
<body>
<!-- 格式验证: 例如 手机号, 邮箱... -->
<script>
// prompt : 收集用户录入数据的弹窗
var phone = prompt('请输入手机号:')
console.log('phone:', phone)
// 手机号规则
// 1. 11位 数字
// 2. 1 开头 正则: ^ 代表字符串开头
// 3. 第二位 3-9
// 正则符号 $: 代表字符串的结尾
var reg = /^1[3-9]\d{9}$/
// test: 测试
// 正则对象.测试(字符串): 判断字符串是否符合正则表达式的要求
var r = reg.test(phone) //返回值是布尔类型
console.log(r ? '是手机号' : '非手机号')
// 正则大全: http://www.codece.com/archives/270
</script>
</body>
</html>