关于javascript:ES2018ES9ES2021ES12新特性概览

本文简略记录了一下ES2018到ES2021中新增的个性,能够点击新个性具体理解一下。

ES2018/ES9

非转义序列的模板字符串

移除了在带标签的模板字符串中转义序列的语法限度
之前,\u开始一个unicode本义,\x开始一个十六进制本义,\后跟一个数字开始一个八进制本义。这使得创立特定的字符串变得不可能,例如Windows文件门路 C:\uuu\xxx\111

正则表达式Unicode本义

之前, 能够通过字符集的名称来匹配字符, 即s代表空白
/^\s+$/u.test(' ') // true
在es9,增加了Unicode属性本义,模式为\p{...}\P{...},在正则表达式应用标记u

/^\p{White_Space}+$/u.test(' ') // 空格
// true
/^\p{Script=Greek}+$/u.test('μετά') // 希腊字母
// true
/^\p{Script=Latin}+$/u.test('Grüße') // 匹配拉丁字母

正则表达式s标记

之前.能够匹配任意字符,除了换行符
es9后,能够通过标记s,这样.就能够匹配换行符
/hello.es9/s.test('hello\nes9') //true

RegExp named capture groups(正则表达式命名捕捉组)

捕捉分组和非捕捉分组

()示意捕捉分组,()会把每个分组里的匹配的值保存起来(存储在内存中),捕捉的子序列稍后能够通过 Back 援用(反向援用) 在表达式中应用
(?)结尾的就是非捕捉分组,不会将匹配的值保存起来,也不能前面援用,其中?:、?=、?<=等都是非捕捉元,应用这些非捕捉元的分组为非捕捉分组
捕捉分组都是通过索引编号的, 这样代码可读性差

const reg = /(\d{4})-(\d{2})-(\d{2})/u;
const matched = reg.exec('2018-12-31');
matched[0];  // 2018-12-12
matched[1];  // 2018
matched[2];  // 12
matched[3];  // 31

命名捕捉组

es9中,容许命名捕捉组应用符号?<name>, 小括号中匹配内容的名称放在groups里,进步了代码的可读性

const reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u
const matched = reg.exec('2018-12-31')
matched.groups.year;  // 2018
matched.groups.month;  // 12
matched.groups.day;  // 31

命名捕捉组也能够应用在replace()办法中
例如将日期转换为“年月日”格局:

const reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
'2018-12-31'.replace(reg, '$<year>年$<month>月$<day>日');
// 2018年12月31日

正则表达式反向断言(lookbehind)

正向后行断言:?=

模式: (?=pattern)
exp1(?=exp2): 查找前面为exp2的exp1

const reg = /runoob(?=[\d+])/g //匹配数字后面的runoob
123456runoob123runoobbdhh // 只会匹配第一个runoob
23runoob456runoob789 //两个都好匹配到

负向后行断言: ?!

模式: (?!pattern)
exp1(?!exp2): 查找前面不为exp2的exp1

const reg = /runboo(?![0-9]+)/g // 匹配前面不是数字的runboo
1233runboo-google12runoob1233 // 匹配第一个

正向后行断言(es9): ?<=

模式: (?<=pattern)
(?<=exp2)exp1: 查找后面是exp2的exp1

const reg = /(?<=[0-9]+)runboo/g //匹配后面是数字的runboo
1234google123runboo456 // 匹配runboo
123googlerunboo123runboo456 // 匹配第二个

负向后行断言(es9):?<!

模式: (?<!pattern)
(?<!exp2)exp1: 查找后面不是exp2的exp1

const reg = /(?<=[0-9]+)runboo/g //匹配后面不是数字的runboo
1234google123runboo456 // 不能匹配到runboo
123googlerunboo123runboo456 // 匹配第一个

扩大运算符(…)

之前...只能用于数组,es9后,也能够用于对象了,用法和数组一样

Promise.finally()

没有参数
之前的Promise的后果要么是胜利then要么是失败catch,使得有些公共逻辑代码必须在两个回调函数外面写(例如:执行状态批改, 删除对话等)
而后就有了finally(),逻辑只放在一个中央,无论Promise运行胜利还是失败,都会运行

new Promise((reslove, reject) => {
  // ...
}).then((res) => {
  // reslove
}).catch((err) => {
  // reject
}).finally(() => {
  // complete
});

异步迭代

es8中,能够应用async/await在同步的写法中执行异步函数,然而在循环中,循环仍然放弃同步,即在外部异步函数调用之前循环曾经全副实现

async function foo(array) {
  for (let i of array) {
    await doSomething(i);
  }
}

es9引入了异步迭代器(asynchronous iterators),使await能够和for...of循环一起应用

async function foo (array) {
    for await (let i of array) {
        doSomething(i)
    }
}

ES2019/ES10

可选的catch

try {
    //...
} cath(unused) {
    // ...
}
//能够省略没有应用到的catch里的变量
try {
    //...
} catch {
    //...
}

Symbol.prototype.description

只读属性,返回Symbol对象的可形容的字符串

Symbol('desc').description // desc

Object.fromEntries(iterable)

将键值对列表转换为对象
Object.fromEntries() 执行与 Object.entries 互逆的操作:

//将对象转换为数组
const arr = Object.entries(obj) // [[key, value]]的模式

// 还原回来
const obj = Object.fromEntries(arr);

将map对象转为对象:

const map = new Map();
map.set('one', 1);
map.set('two', 2);

const obj = Object.fromEntries(map); // {one: 1, two: 2}

解决URL的查问字符串:

const paramsString = 'param1=foo&param2=baz';
const searchParams = new URLSearchParams(paramsString); // { param1: 'foo', param2: 'baz'}

String.prototype.{trimStart, trimEnd}

别离为去掉字符串右边和左边的空格,与trimLeft()和trimRight()雷同
对于Web兼容性,trimLeft() 和trimRight() 将保留为trimStart() 和trimEnd() 的别名。

Array.prototype.{flat, faltMap}

flat([level])办法能够将多维数组展平成一维数组,且有空值时,会抛弃; 可选参数level指定开展几层

// 以前应用concat或reduce
const arr = ['a', 'b', ['c', 'd']];
const flattend = [].concat.apply([], arr);
// const flattend = [].concat(...arr);

flatMap()办法将map()和flat()组合成一个办法


const arr2 = [[7.1], [8.1], [9.1], [10.1], [11.1]];
//想要删除我的项目,只需返回[]
// do not include items bigger than 9
arr.flatMap(value => {
  if (value >= 10) {
    return [];
  } else {
    return Math.round(value);
  }
}); 
// [7, 8,9]

ES2020/ES11

String.prototype.matchAll(regexp)

返回一个蕴含所有匹配正则表达式的后果及分组捕捉组的迭代器
regexp参数必须要设置全局模式g,否则会抛出异样
之前咱们通过在循环中调用regexp.exec()来获取所有匹配项信息

const regexp = RegExp('foo[a-z]*','g');
const str = 'table football, foosball';

let match;
while ((match = regexp.exec(str)) !== null) {
  console.log(`Found ${match[0]} start=${match.index} end=${regexp.lastIndex}.`);
  // expected output: "Found football start=6 end=14."
  // expected output: "Found foosball start=16 end=24."
}

// matchAll
const matches = str.matchAll(regexp);

for (const match of matches) {
  console.log(`Found ${match[0]} start=${match.index} end=${match.index + match[0].length}.`);
}
// expected output: "Found football start=6 end=14."
// expected output: "Found foosball start=16 end=24."

import()

按需动静导入模块
在之前,依据须要导入模块时只能应用require()
@babel/preset-env中曾经蕴含了@babel/plugin-syntax-dynamic-import,所有只需配置@babel/preset-env
import()返回的是一个Promise对象

// module.js
export default {
  name: 'shenjp'
}

// index.js
if (true) {
  let module = import('./module.js');
  console.log(module); // Promise {<pending>
  module.then(data => console.log(data)); // Module {default: {name: "shenjp"}, __esModule: true, Symbol(Symbol.toStringTag): "Module"}
}

import.meta

为以后运行的模块增加了一个特定host元数据对象

<script type="module" src="my-module.mjs"></script>
console.log(import.meta); // { url: "file:///home/user/my-module.mjs" }

BigInt:内置对象

能够示意任意大的整数,本来JavaScript只能示意2^53 -1以内的数字
定义一个BigInt:

// 1、在数字字面量前面加一个n
const big = 10n
// 2、调用BigInt()
const big2 = BigInt(9007199254740991) // 9007199254740991n
const big3 = BigInt('9007199254740991') // 9007199254740991n

typeof big2 // bigint

// 带小数的运算会被取整
5n/2n // 2n

留神: 不能用于Math对象中的办法;不能和Number实例混合运算,必须要转换为同一种类型才行(在BigInt转Number时,留神可能会失落精度)
BigInt能够和+、*、-、**(次方)、%和除>>>(因为BigInt都是有符号的)之外的位操作

空值合并运算符(??)

只会右边的值严格等于null或undefined时才应用左边的值

'' || 'default' // default
'' ?? 'default' // ''
0 || 'defa' // defa
0 ?? 'defa' // defa

可选链

当咱们在一个深的树形构造中查找一个属性值会像上面这样:

const name = data && data.info && data.info.name

//应用?.
const name1 = data?.info?.name
//还能够与空值合并运算符搭配应用
const name2 = data?.info?.name ?? 'jack'

// 其余应用
a?.b // a === null ? undefined : a.b
a?.[x] // a === null ? undefined : a[x]
a?.b() // a === null ? undefined : a.b()
a?.() // a === null ? undefined : a()
a?.b[3].c?.(x).d // a == null ? undefined : a.b[3].c == null ? undefined : a.b[3].c(x).d

// optional deletion
delete a?.b // a === null ? true : delete a.b

不反对可选链的:

1、可选的构造函数: new a?.()
2、可选的模块字符串: a?.`string`
3、可选的属性赋值: a?.b = c
4、可选的super: super?.(), super?.foo

globalThis

以前,在不同的JavaScript环境中获取全局对象须要不同的的语句,Web中能够通过window、self(Web workers)、frames取到全局对象,在Node.js中,应用global取得
当初能够对立应用globalThis来获取全局对象

Promise.allSettled()

返回一个在给定的promise都曾经fulfilled或rejected后的promise,并带有一个对象数组,每个对象示意对应的promise后果

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

Promise.allSettled(promises).
  then((results) => results.forEach((result) => console.log(result.status)));

// fulfilled
// rejected

ES2021/ES12

String.prototype.replaceAll(searchValue, replaceValue)

已有的String.prototype.replace只能替换第一个匹配的,如果须要匹配所有,须要应用正则如果加全局合乎g
还能够应用split+join的办法达到替换所有
留神: replaceAll时,searchValue如果是正则然而是非全局时(即没有加g关键字),会引发异样,

Promise.any()

接管一个Promise可迭代对象,只有其中的一个promise胜利,就返回那个曾经胜利的promise,如果没有一个promise胜利,则返回一个失败的Promise
如果传入的参数是一个空的迭代对象,则会返回一个已失败状态的Promise
如果传入的参数不蕴含任何promise,则返回一个异步实现的promise
该办法会返回第一个胜利的 promise 。只有有一个 promise 胜利此办法就会终止,它不会期待其余的 promise 全副实现。

Promise.any([
  fetch('https://v8.dev/').then(() => 'home'),
  fetch('https://v8.dev/blog').then(() => 'blog'),
  fetch('https://v8.dev/docs').then(() => 'docs')
]).then((first) => {
  // Any of the promises was fulfilled.
  console.log(first);
  // → 'home'
}).catch((error) => {
  // All of the promises were rejected.
  console.log(error);
});

Logical Assignment Operators(逻辑赋值操作符)

a ||= b // a || (a  = b)
a ??= b
a &&= b

数字分隔符(_)

在二进制、十六进制、BigInt中都能够应用

const x = 1000000000
const y = 1000_000_000
x === y // true

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理