1. ES7 新特性
1.1 Array.prototype.includes()
该方法是用来查找数组中是否存在某个值,如果存在返回true ,如果不存在则返回false。而es6则是通过indexOf()来判断某个值是否在数组中,但是返回值是下标,如果不存在则返回-1。相较于仅仅判断某个值是否在数组中,使用includes更方便。
const arr = [1, 3, 4, 2, 8]
console.log(arr.includes(3)) // true
console.log(arr.includes(9)) // false
1.2 ** 幂运算
通过m**n来计算m的n次幂。对照于Math.pow(m, n)。
console.log(2 ** 10) // 1024
console.log(Math.pow(2, 10)) // 1024
2. ES8 新特性
2.1 async和await
async 和 await 提供了在不阻塞主线程的情况下使用同步代码实现异步访问资源的能力,并且使得代码逻辑更加清晰。async函数的返回值为promise对象,promise对象的结果由async函数执行的返回值决定。
① async函数返回的值不是promise对象,则其返回的结果就是成功的promise对象
async function fn () {
return 'es8'
}
const result = fn()
console.log(result)
② 抛出错误,返回的结果是一个失败的promise对象
async function fn () {
throw new Error('失败的promise')
}
const result = fn()
console.log(result)
③ 返回的值为promise对象,则async返回的结果由返回的promise对象来决定。即如果返回的值是成功的promise对象,则async返回的结果就是成功的promise对象。
async function fn () {
return new Promise((resolve, reject) => {
// resolve('成功的数据')
reject('失败的promise')
})
}
const result = fn()
console.log(result)
2.2 await 表达式
- await 必须写在async函数中(单向依赖)
- await 右侧的表达式一般为promise对象
- await 返回的是promise成功的值
- await 的promise失败了,就会抛出异常,需要通过try...catch捕获处理
const p = new Promise( (resolve, reject) => {
resolve({
content: 'success',
name: 'p'
})
// reject('失败')
})
async function xxx () {
try {
let result = await p
console.log(222, result)
} catch (e) { // 捕获失败
console.log(222, e)
}
}
xxx()
2.3 async 和 await 结合读取文件
// es8.js
// 1. 引入fs模块
const fs = require('fs')
function readStudy () {
return new Promise ( (resolve, reject) => {
fs.readFile('./es6/es7-11/study.md', (err, data) => {
if (err) reject(err) // 如果失败
resolve(data)
})
})
}
function readMoon () {
return new Promise ( (resolve, reject) => {
fs.readFile('./es6/es7-11/moon.md', (err, data) => {
if (err) reject(err) // 如果失败
resolve(data)
})
})
}
// 声明一个async函数
async function main () {
// 获取study内容
let study = await readStudy()
// 获取mooon内容
let moon = await readMoon()
console.log(study.toString())
console.log(moon.toString())
}
main()
2.4 async 和 await 结合发送Ajax请求
// 发送Ajax请求,返回结果是promise对象
function sendAjax (url) {
return new Promise ( (resolve, reject) => {
// 1. 创建对象
const x = new XMLHttpRequest()
// 2. 初始化
x.open('GET', url)
// 3. 发送
x.send()
// 4. 事件绑定
x.onreadystatechange = function () {
if (x.readyState === 4) {
if (x.status >= 200 && x.status < 300) {
resolve(x.response)
} else {
reject(x.status)
}
}
}
})
}
// promise then的测试
const ajaxResult = sendAjax("https://api.apiopen.top/getJoke").then( val => {
// console.log(val)
}, err => {})
console.log(ajaxResult)
// async await测试
async function asyncAjax () {
let asyncResult = await sendAjax("https://api.apiopen.top/getJoke")
console.log(asyncResult)
}
asyncAjax ()
2.5 对象方法扩展
- Object.values()
- Object.entries()
- Object.getOwnPropertyDescriptors()
const JJJ = {
name: 'jjj',
cities: ['beijing', 'nanjing', 'hangzhou'],
directions: ['东', '西', '南', '北']
}
console.log(Object.keys(JJJ))
console.log(Object.values(JJJ))
console.log(Object.entries(JJJ))
console.log(new Map (Object.entries(JJJ)))
// 对象的属性特性描述对象(可写,可删除,可枚举)
console.log(Object.getOwnPropertyDescriptors(JJJ))
3. ES9 新特性
在es9中对象提供了像数组一样的rest参数和扩展运算符。es6是数组引入rest参数和扩展运算符。
function connect ( { host, port, ...user} ) {
console.log(host, port, user)
}
connect({
host: 'localhost',
port: 123456,
username: 'root',
password: 'root',
type: 'master'
})
3.1 命名捕获分组
ES9 之前的命名捕获是通过(.*)的方式,含义为:匹配除换行符之外的字符零次或多次的字符串并获取该匹配。通过输入的结果,可以通过下标的方式获取,如结果如下,result[1]为第一个匹配的字符串,result[2]为第二个匹配的字符串。
推荐一篇很全的正则表达式的文档:正则表达式
// 1. 声明字符串
let str = '<a href="http://baidu.com">百度</a>'
// 提取 url 与 标签文本
const reg = /<a href="(.*)">(.*)<\/a>/
// 执行
const result = reg.exec(str)
console.log(result)
在ES9中对该规则进行了扩展,可以通过对获取的匹配进行了命名的方式进行获取,即?<name>为后面匹配的字符串进行了命名处理。
// 1. 声明字符串
let str2 = '<a href="http://baidu.com">百度2</a>'
// 提取 url 与 标签文本
const reg2 = /<a href="(?<url>.*)">(?<text>.*)<\/a>/
// 执行
const result2 = reg2.exec(str2)
console.log(result2)
可以通过.groups的方式进行获取匹配的字符串。通过名字进行获取字符串,可以避免如果字符放置的顺序发生更改,通过名字获取内容不变。如果通过下标获取,则下标的内容更改,获取的内容也就发生了改变。对于获取url携带的字段内容非常有用。
console.log(result2.groups.text)
console.log(result2.groups.url)
3.2 反向断言
先了解一下正向断言。根据要匹配的字符串的后面的字符(字符串)进行判断和获取。
// --正向断言 根据要匹配的字符串的后面的字符进行判断
let str3 = 'hfoahfihaofhfbaidudjlajbaiduadajl88888哈哈'
const reg3 = /\d+(?=哈)/ // 后面的字符是哈才满足条件
const result3 = reg3.exec(str3)
console.log(result3)
涉及到的正则规则:
+ | 匹配前面的子表达式一次或多次。例如,“zo+ ”能匹配“zo ”以及“zoo ”,但不能匹配“z ”。+等价于{1,}。 |
---|---|
(?=pattern) | 正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
而反向断言,则是根据要匹配的字符串的前面的字符(字符串)进行判断和获取。用于在服务器路径中匹配想获取的值较多。
// --- 反向断言 根据要匹配的字符串的前面的字符进行判断
let str4 = 'hfoahfihaofhfb888aidudjlajbaiduadajl88888哈哈'
const reg4 = /(?<=b)\d+/ // 后面的字符是哈才满足条件
const result4 = reg4.exec(str4)
console.log(result4)
涉及到的正则规则:
+ | 匹配前面的子表达式一次或多次。例如,“zo+ ”能匹配“zo ”以及“zoo ”,但不能匹配“z ”。+等价于{1,}。 |
---|---|
(?<=pattern) | 反向肯定预查,与正向肯定预查类拟,只是方向相反。例如,“(?<=95|98|NT|2000)Windows ”能匹配“2000Windows ”中的“Windows ”,但不能匹配“3.1Windows ”中的“Windows ”。 |
3.3 dotAll模式
非dotAll模式下的匹配。对于匹配获取标签中的内容时,要考虑将空格、换行符等匹配上过滤,每次遇到要通过\s+进行多次匹配。(.*?)中的?作用是禁止贪婪。
let str5 =
`<ul>
<li>
<a> 金鼎鲜花 </a>
<p> 地址: 河北省石家庄市新华区新华路100-2 </p>
</li>
<li>
<a> 蛋糕店 </a>
<p> 地址: xx区xx路46号 </p>
</li>
</ul>`;
const reg5 = /<li>\s+<a>(.*?)<\/a>\s+<p>(.*?)<\/p>/ //?禁止贪婪
const result5 = reg5.exec(str5)
console.log(result5)
dotAll模式下的操作为通过在匹配规则后加上s,表示 . 元字符也能匹配换行符,不用 \s+ 进行特殊判断。用 .*? 进行即可。因为元字符可以匹配任意字符了。
const reg6 = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs
let result6;
let resData = []
while (result6 = reg6.exec(str5)) {
// console.log(result6)
resData.push({
name: result6[1],
address: result6[2]
})
}
console.log(resData)
4. ES10 新特性
4.1 对象扩展方法
es10中有一个新方法,即Object.fromEntries(),与es8的Object.entries()实现功能相反。Object.fromEntries()是将二维数组和Map结构转换为对象(键和值的方式),而Object.entries()方法是将对象转化为二维数组。
// 对象扩展方法 Object.fromEntries 将二维数组转化为对象
const ArrToObject = Object.fromEntries([
['name', '金鼎鲜花'],
['adress', '河北省石家庄市新华区新华路100-2']
])
console.log(ArrToObject)
//Map
const m = new Map()
m.set('name', '金鼎鲜花')
m.set('adress', '河北省石家庄市新华区新华路100-2')
console.log(m)
const MapToObject = Object.fromEntries(m)
console.log(MapToObject)
关于Object.entries()的具体操作如下。转化为的数组,将键值对信息放在每一个数组里,数组的0下标位置的内容为键,1下标位置的内容为值。
// 逆运算 将对象转化为数组
const ObjectToArr = {
'name': '金鼎鲜花',
'adress': '河北省石家庄市新华区新华路100-2'
}
console.log(Object.entries(ObjectToArr))
本人还遇到一种情况是:在使用Object.fromEntries()和Object.entries()时,控制台报了一个错误Uncaught TypeError: Object.fromEntries is not a function。这种错误是由于浏览器版本不兼容所导致的(IE6-11浏览器不兼容)。杜宇两者的浏览器的兼容情况如下图。
4.2 字符串方法扩展
es10 提供了两个对于字符串首或尾删除空格的方法:str.trimStart()和str.trimEnd()。红色点点为空格部分。
let str = ' 金鼎 鲜花 '
console.log(str)
console.log(str.trim())
console.log(str.trimStart())
console.log(str.trimEnd())
浏览器兼容情况:(IE6-11浏览器不兼容)
4.3 数组方法扩展
ES10中提供了数组降维操作flat和map结构降维操作flatMap。其中对于flat(n)来说,n表示多维数组降维的深度,如果为2,则多维数组降2层维度,空则默认降1维。
// 将多维数组转化为低维数组 flat(n) n为降维的深度 默认值为1
const arr = [1, 2, 3, 4, [4, 5, 6]]
console.log(arr.flat())
const arr2 = [1, 2, 3, 4, [4, 5, 6, [3, 8, 4]]]
console.log(arr2.flat(2), arr2.flat())
// faltMap
const arr3 = [1, 2, 3]
const res1 = arr3.map(item => item * 10)
const res2 = arr3.flatMap(item => [item * 10, item * 3])
console.log(res1, res2)
浏览器兼容情况:(IE6-11浏览器不兼容)
4.4 Symbol.prototype.description
获取Symbol的字符串描述。
let s = Symbol('金鼎鲜花')
console.log(s.description) // 金鼎鲜花
5. ES11 新特性
5.1 私有属性(#name的形式)
class Person {
// 公有属性
name
// 私有属性
#age
#weight
constructor(name, age, weight) {
this.name= name
this.#age = age
this.#weight = weight
}
getPersonInfo () {
console.log(this.name, this.#age, this.#weight)
}
}
const girl = new Person('lucy', 16, '38kg')
console.log(girl)
console.log(girl.name)
girl.getPersonInfo()
console.log(girl.#age) // Uncaught SyntaxError: Private field '#age' must be declared in an enclosing class
5.2 字符串扩展String.prototype.matchAll
let str =
`<ul>
<li>
<a> 金鼎鲜花 </a>
<p> 地址: 河北省石家庄市新华区新华路100-2 </p>
</li>
<li>
<a> 蛋糕店 </a>
<p> 地址: xx区xx路46号 </p>
</li>
</ul>`;
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs
const result = str.matchAll(reg)
const arr = [...result]
console.log(arr)
5.3 可选链操作符
?. 对象类型的参数深度较深的情况。
A?.B?.C可选链操作符是判断A存在,如果存在就继续判断A.B的存在,如果两者均存在,则继续执行判断A.B.c是否存在,存在则取A.B.C。相当于的效果:判断传的参数A存在的情况下,才能继续取A里面的属性值。下面的代码的config?.db?.host就等价于config && config.db && config.db.host。为了防止在编写代码的时候,要一层一层的判断传的参数是否存在或参数的某个属性值是否存在,存在的情况下才能继续取想要的值,要是不去判断,未传参而去使用,会报错。
function main (config) {
// const dbHost = config && config.db && config.db.host
const dbHost = config?.db?.host
console.log(dbHost)
}
main({
db: {
host: 'localhost',
username: 'root'
},
cache: {
host: 'http://localhost/',
username: 'root2'
}
})
浏览器兼容性:
5.4 动态import加载
import()函数返回promise对象。根据模块加载的需求(用的时候)进行按需引入模板,动态引入,不用一开始全部引入。
// html文件
<script src="./es10/app.js" type="module" charset="utf-8"></script>
<body>
<button id="btn">点击</button>
</body>
// app.js
const btn = document.getElementById('btn')
btn.onclick = function () {
import('./hello.js').then(result => {
result.hello()
})
}
// hello.js
export function hello () {
alert('hello!!!')
}
浏览器兼容性:
5.5 bigInt()
浮点型不可以。用于大数值运算。
console.log(BigInt(123)) // 123n
console.log(BigInt(123.111)) // Uncaught RangeError: The number 123.111 cannot be converted to a BigInt because it is not an integer
bigInt只能与bigInt进行运算,否则会报错:Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions.
let nMax = Number.MAX_SAFE_INTEGER
console.log(nMax)
console.log(nMax + 1)
console.log(nMax + 2)
console.log(BigInt(nMax) + 2) // 报错
console.log(BigInt(nMax) + BigInt(2))
5.6 绝对全局对象globalThis
如果需要对全局对象进行操作,可以使用此忽略环境使用全局对象。
^-^ *_* ^-^ ***** 完 · 结 *****