简单介绍一点 ES6-ES12 的新特性🥺👉👈🥺

298 阅读7分钟

「这是我参与2022首次更文挑战的第33天,活动详情查看:2022首次更文挑战

概况

由于每年都有新语法的发布,ES的版本号都会随之递增,关于ES版本的取名根据发布的年份来定,但是ES6也算是一个泛指,表示ES5后的下一代标准

发布年份缩写昵称
2016ES2016、ES7
2017ES2017、ES8
2018ES2018、ES9
2019ES2020、ES10
2020ES2020、ES11
2021ES2021、ES12

使用新特性时,若项目babel不支持编译,可以安装相应的babel插件。更多配置可以查看babel插件列表,或者直接引入@babel/preset-env,基本包含所有的新特性(babel7以上)

ES7(ES2016)

Array.prototype.includes()

之前有find,findIndex,indexOf方法用来寻找对象或者数组中的值和索引,一个是为了在语义上清晰的描述这个场景,一个是为了判断NaN。

[1, 2, NaN].includes(NaN);// true
[1, 2, NaN].includes(3,1);// false

幂运算符

let cubed = 2 ** 3;
// 相当于2 * 2 * 2   Math.Pow(2,3)

ES8(ES2017)

Object.values/Object.entries

只返回对象自身所有可遍历的值,查看当前是否可遍历 可以通过getOwnPropertyDescriptors获取

obj = {
  a: 1,
  b: 2
}
Object.values(obj) //[1,2]
Object.entries(obj) //[['a',1],['b',2]]

Object.getOwnPropertyDescriptors()

获取当前对象的数据属性

  • value — 属性实际的值
  • writable — 属性的值是否可以被修改
  • get — 获取函数,在读取属性时调用
  • set — 设置函数,在写入属性时调用
  • configurable — 属性是否可以通过 delete 删除并重新定义,是否可以修改它的特 性,以及是否可以把它改为访问器属性
  • enumerable-是否可枚举
let obj = {
  a: 1
}

Object.getOwnPropertyDescriptors(obj)

// { 
//   a: { 
//     value: 1, 
//     configurable: true, 
//     enumerable: true, 
//     writable: true 
//   } 
// }

由于Object.assign不能拷贝get属性和set属性,可以通过Object.create和getOwnPropertyDescriptors实现对象的拷贝。

const obj = {
  set c(v) {
    console.log('设置c')
    c = v;
  },
};
newObj = Object.assign({}, obj);
newObj.c = 1 //
newObj1 = Object.create({}, Object.getOwnPropertyDescriptors(obj))
newObj.c = 1 //设置c

String padding(目标长度,添加字符)

计算时分秒,为了规范成hh:mm:ss,可以选用下边的方法

"3".padStart(2, "00"); // '03'
 
"x".padEnd(5, "ab"); // 'xabab'

异步函数 async/await

generator函数的语法糖,可以以同步写法实现异步的操作,async函数返回一个 Promise 对象,内部return语句返回的值,会成为then方法回调函数的参数

generator函数需要手动去调用next方法获取值,async会自动执行next,最终输出一个promise。

function fakeRequest() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("请求成功");
    }, 2000);
  });
}
 
async function getData() {
  console.log("start");
  const res = await fakeRequest();
  console.log(res);
  console.log("end");
}
getData();
//start
//请求成功
//end

ES9(ES2018)

扩展运算符

通常用来进行一些数据的分裂或者合并

let obj={a:1}
let res={
  ...obj,
  b:2
}

Promise.prototype.finally

常见的场景是

  • 关闭数据请求时的laoding状态
  • 不管前面的操作成功或是失败,最后都要执行一个指定的回调函数操作
Promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

异步遍历器 for await...of

使用for.. of 遍历异步操作时,使用await进行顺序执行。

使用for await...offor...of的实现逻辑循环自动调用这个对象,执行这个异步的操作得到一个 Promise 对象后。await用来处理这个 Promise 对象,拿到结果,再把得到的值(item)传入for...of的循环体。

function Gen(time) {
  return new Promise((resolve, reject) => {
    setTimeout(function () {
      resolve(time)
    }, time)
  })
}

async function test() {
  console.log('开始', Date.now())
  let arr = [Gen(2000), Gen(5000), Gen(8000)]
  for await (let i of arr) {
    console.log(Date.now(), await i);
  }
  console.log('结束', Date.now())
}

test()

// 开始 1645690296443
// 1645690296443 2000
// 1645690298444 5000
// 1645690301446 8000
// 结束 1645690304449

正则表达式

dotAll模式

.可以匹配大部分字符,除了一些特殊的比如换行符\n、回车符\r、还有一些分隔符,为了匹配所有的字符增加一个 s/dotAll 标志。

而且还引入了一个dotAll属性,返回一个布尔值,表示该正则表达式是否处在dotAll模式。

'ee.\ne'.match(/.+/g)  //['ee.','e']
'ee.\ne'.match(/.+/s)  //['ee.↵e']
let reg=/.+/s
reg.dotAll //true
具名匹配

?<>将每组匹配出来的结果指定一个名字,获取group直接得到匹配的结果。

const reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
console.log(reg.exec('2020-02-01'))
const groups = reg.exec('2020-02-01').groups
const {year, month, day} = groups
console.log(year, month, day)//2020 02 01
后行断言(?<=y)x

“先行断言”指的是,x只有在y前面才匹配,必须写成/x(?=y)/

“先行否定断言”指的是,x只有不在y前面才匹配,必须写成/x(?!y)/

'100%11'.match(/\d+(?=%)/g)  // ['100'] 先行断言,只匹配百分号之前的数字
'44e33r'.match(/\d+(?!%)/g)//['44','33'] 先行否定断言
'3$11e2'.match(/(?<=\$)\d+/g)  // ['11'] 后行断言,只匹配在$后边的数字
'3$1ee2'.match(/(?<!\$)\d+/g) //['3','2'] 后行否定断言

ES10(ES2019)

Object.fromEntries()

Object.entries 的逆向操作,接受一个二维数组或者 Map(),返回一个对象。多用于转换Map().

const map = new Map();
map.set('name', 'taotao');
map.set('age', '25');

Object.fromEntries(map);
//{
//   name: 'taotao',
//   age: 25
// }

Object.fromEntries([
  ['name', 'taotao'],
  ['age', 25]
]);

//{
//   name: 'taotao',
//   age: 25
// }

trimStart()、trimEnd()

对 str.trim()的补全。

' input'.trimStart(); // input
'input '.trimEnd(); // input

flat()

抹平数组

const arr = [1,2,3,[4,5,6,[7,8,9]]];
arr.flat(); // [1,2,3,4,5,6,[7,8,9]] // 默认深度1
arr.flat(1); // [1,2,3,4,5,6,[7,8,9]] // 深度 = 维度 - 1
arr.flat(2); // [1,2,3,4,5,6,7,8,9] // 深度 = 维度 - 1
arr.flat(Infinity); // [1,2,3,4,5,6,7,8,9] // Infinity -> 打成一维数组

flatMap()

flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 连着深度值为1的 flat 几乎相同。

const arr1 = [1, 2, 3, 4];
 
arr1.map(x => [x * 2]);
// [[2], [4], [6], [8]]
 
arr1.flatMap(x => [x * 2]);
// [2, 4, 6, 8]
 
// only one level is flattened
arr1.flatMap(x => [[x * 2]]);
// [[2], [4], [6], [8]]

Symbol.description

获取 Symbol 的描述字符串

const syb = Symbol('taotao');
 
console.log(syb.description); // taotao

ES11(ES2020)

Promise.allSettled()

把全部的异步操作结果都返回回来。

(async () => {
  const res = await Promise.allSettled([
    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(5000);
      }, 5000);
    }),
    new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(2000);
      }, 2000);
    }),
  ]);

  console.log(res);
})()

// [
//   {
//     "status": "fulfilled",
//     "value": 5000
//   },
//   {
//     "status": "rejected",
//     "reason": 2000
//   }
// ]

class 的私有变量

私有变量 # 必须以 # 访问

class Person {
  // 公有属性
  name;
  // 私有属性
  #age;
  #weight;

  constructor(name, age, weight) {
    this.name = name;
    this.#age = age;
    this.#weight = weight;

  }

  log() {
    console.log(this.name);
    console.log(this.#age);
    console.log(this.#weight);
  }
}

const girl = new Person('2B', 150, '280kg');
console.log(girl);
girl.age = 18; // 新增属性
girl.#age = 18; // 报错

matchAll

一般用于爬虫抓取文案之类

const str =
  '<ul>' +
  '<li>' +
  '<a>肖生克的救赎</a>' +
  '<p>上映日期:1994-09-1</p>' +
  '</li>' +
  '<li>' +
  '<a>阿甘正传</a>' +
  '<p>上映日期:1994-07-6</p>' +
  '</li>' +
  '<\/ul>'
const reg = /<li>.*?<a>(.*?)<\/a>(.*?)<p>(.*?)<\/p>/sg

//调用方法
const result = str.matchAll(reg);

for (let v of result) {
  console.log(v);
}

可选链

ts 的可选链被 js 原生的支持了。

const person = {
  a: {
    b: 'bb',
    c: 'cc'
  }
}

const a1 = person && person.a && person.a.b;
const b1 = person?.a?.b;

BigInt

新的基础数据类型 正常的js只能表达 -(2^53 - 1)2^53 - 1 之间的数值(包含边界值)

let a = BigInt(1);
let b = BigInt(1.2);// 报错
let number = Number.MAX_SAFE_INTEGER; // 9007199254740991
let numberAdd1 = number + 1; // 9007199254740992
let numberAdd2 = number + 2; // 9007199254740992
let numberAdd3 = number + 3; // 9007199254740992
 
let bigIntNumberAdd1 = BigInt(number) + 1; // 报错
let bigIntNumberAdd2 = BigInt(number) + BigInt(2); // 9007199254740993n

??

ts??js 原生的支持了,除了 nullundefined 之外都是真。

let user = {
  u1: 0,
  u2: false,
  u3: null,
  u4: undefined,
  u5: '',
}
let u1 = user.u1 ?? 'a1'  // 0
let u2 = user.u2 ?? 'a2'  // false
let u3 = user.u3 ?? 'a3'  // a3
let u4 = user.u4 ?? 'a4'  // a4
let u5 = user.u5 ?? 'a5'  // ''

ES12(ES2021)

||=、&&=、??=

let a = 1;
let b = 2;
 
b ||= a; // b = b || a
b &&= a; // b = b && a
b ??= a; // b = b ?? a

数字分隔符 _

const number = 1_000_000_000; // 一亿
const phone = 138_1234_1234; // 号码
const test1 = 138__1234_1234; // 报错
const test2 = _138_1234_1234; // 变量名

replaceAll

到了校验的作用,确保替换所有

let str = 'abc aef ah';
 
str.replace(/a/g, '*');
str.replaceAll('a', '*');
 
str.replaceAll(/a/, '*'); // 报错 -> 必须加 g

Promise.any()

返回第一个成功的异步操作结果。

(async () => {
  const res = await Promise.any([
    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(5000);
      }, 5000);
    }),
    new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(2000);
      }, 2000);
    }),
  ]);

  console.log(res); // 5000
})();

返回第一个完成的异步操作结果。

(async () => {
  const res = await Promise.race([
    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(5000);
      }, 5000);
    }),
    new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(2000);
      }, 2000);
    }),
  ]);

  console.log(res); // 报错
})();

垃圾回收 FinalizationRegistry

const registry = new FinalizationRegistry((value) => {
  console.log('变量被回收了:', value)
})
 
(() => {
  const a = {a:123}
  registry.register(a,12)
})();

本地化 Intl

是ECMAScript国际化API的命名空间,它提供对语言敏感的字符串比较、支持数字格式化以及日期和时间的格式化。

const date = new Date();
const str = new Intl.DateTimeFormat('zh').format(date); // 2022/02/28