最全 ECMAScript 攻略之 ES2020-ES12

2021 提案为 ECMAScript 新增了下表中所描述的特性

20210519154851

String.protype.replaceAll

在 ES2021 之前,要替换掉一个字符串中的所有指定字符,我们可以这么做:

const str = "a+b+c+";
const newStr = str.replace(/\+/g, "?");
console.log(newStr); //a?b?c?

// 获取使用 split,join进行字符串分割
const queryString = "q=query+string+parameters";
const withSpaces = queryString.split("+").join(" ");
复制代码

现在我们有了更加简洁的方式, ES2021 则提出了 replaceAll 方法,并将其挂载在 String 的原型上,可以这么用:

const str = "a+b+c+";
const newStr = str.replaceAll("+", "?");
console.log(newStr); //a?b?c?

const queryString = "q=query+string+parameters";
const withSpaces = queryString.replaceAll("+", " ");
复制代码

Promise.any

Promise 中有四个主要的方法

name Description
Promise.allSettled 1. 只有等到所有实例都返回结果,不管是fulfilled还是rejected,实例才会结束
2. 有时候,我们不关心异步请求的结果,只关心所有的请求有没有结束即可使用
added in ES2020 ✅
Promise.all 1.只要任意一个 promise 失败,则返回失败的 promise .
2.当所有异步操作都成功后,才返回 promise,返回值组成一个数组
added in ES2015 ✅
Promise.race 只要任意一个 promise 的状态改变(不管成功 or 失败),那么就返回那个 promise added in ES2015 ✅
Promise.any 1.只要其中任意一个 promise 成功,就返回那个已经成功的 promise。
2.如果所有的 promises 都失败/拒绝,就返回一个失败的 promise
added in ES2021 ✅

下面让我们看看Promise.any的代码示例

// demo-1
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);
  });

// demo-2
const pErr = new Promise((resolve, reject) => {
  reject("总是失败");
});

const pSlow = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "最终完成");
});

const pFast = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "很快完成");
});

// 使用 .then .catch
Promise.any([pErr, pSlow, pFast])
  .then((value) => {
    // 返回最先成功的一个promise ,即: pFast-"很快完成"
    console.log(value);
  })
  .catch((err) => {
    // 所有的 promise 都失败时触发
  });

// demo-3
// 使用 顶层-await
try {
  const first = await Promise.any(promises); // 任何一个 promise 成功返回。
  console.log(first);
} catch (error) {
  // 所有的 promise 都失败了
  console.log(error);
}
复制代码

WeakRef

WeakRef 提案主要包含两个新功能:

  • 可以通过 WeakRef 类来给某个对象创建一个弱引用
  • 可以通过 FinalizationRegistry 类,在某个对象被垃圾回收之后,执行一些自定义方法

上述两个新功能可以同时使用,也可以单独使用,取决于你的需求。一个 WeakRef 对象包含一个对于某个对象的弱引用,被称为目标引用

通过弱引用一个对象,可以让该对象在没有其它引用的情况下被垃圾回收机制回收。

WeakRef 主要用来缓存和映射一些大型对象,当你希望某个对象在不被其它地方引用的情况下及时地被垃圾回收,那么你就可以使用它。

function toogle(element) {
  const weakElement = new WeakRef(element);
  let intervalId = null;

  function toggle() {
    const el = weakElement.deref();
    if (!el) {
      return clearInterval(intervalId);
    }
    const decoration = weakElement.style.textDecoration;
    const style = decoration === "none" ? "underline" : "none";
    decoration = style;
  }
  intervalId = setInterval(toggle, 1000);
}
const element = document.getElementById("link");
toogle(element);
setTimeout(() => element.remove(), 10000);
复制代码

FinalizationRegistry 接收一个注册器回调函数,可以利用该注册器为指定对象注册一个事件监听器,当这个对象被垃圾回收之后,会触发监听的事件,具体步骤如下。首先,创建一个注册器:

const registry = new FinalizationRegistry((heldValue) => {
  // ....
});
复制代码

接着注册一个指定对象,同时也可以给注册器回调传递一些参数:

registry.register(theObject, "some value");
复制代码

详细内容参考

逻辑赋值运算符

提出的动机原因:简化判断赋值语句

  1. 函数参数默认值
  2. 从后端获取的数据,不能确定是否是有效值,因此需要判断重新赋值
// bad ?
function example(a) {
  // Default `a` to "foo"
  if (!a) {
    a = "foo";
  }
}

function example(opts) {
  // Ok, but could trigger setter.
  opts.foo = opts.foo ?? "bar";

  // No setter, but 'feels wrong' to write.
  opts.baz ?? (opts.baz = "qux");
}
复制代码
// better ?
function example(opts) {
  // Setters are not needlessly called.
  opts.foo ??= "bar";

  // No repetition of `opts.baz`.
  opts.baz ??= "qux";
}

// 默认参数值
function example(opts = { foo: "foo", baz: "baz" }) {
  return opts;
}
复制代码

详细信息参考ts39-proposal-logical-assignment

逻辑赋值运算符结合了逻辑运算符和赋值表达式。逻辑赋值运算符有两种:

  • 或等于(||=
  • 且等于(&&=
  • ??=

||=

const giveKey = () => {
  return "somekey";
};
let userDetails = { name: "chika", age: 5, room: 10, key: "" };

// userDetails.key = userDetails.key || giveKey();
userDetails.key ||= giveKey();

console.log(userDetails.key);

//output : somekey
复制代码

&&=

const deleteKey = () => {
  return " ";
};
let userDetails = { name: "chika", age: 5, room: 10, key: "990000" };

// userDetails.key = userDetails.key && deleteKey();
userDetails.key &&= deleteKey();

console.log(userDetails.key);

//output : ""
复制代码

??= 空赋值运算符

??= 也被称为空赋值运算符,与上面的非空运算符相关。看看它们之间的联系:

var x = null;
var y = 5;

// x = x ?? y;
console.log((x ??= y)); // => 5
复制代码

仅当值为 nullundefined 时,此赋值运算符才会赋值。上面的例子强调了这个运算符本质上是空赋值的语法糖(类似的语法糖:a = a + b 可写成 a += b )。

接下来,让我们看看这个运算符与默认参数(默认参数是 ES6 引入的新语法,仅当函数参数为 undefined 时,给它设置一个默认值)的区别:

function gameSettingsWithNullish(options) {
  options.gameSpeed ??= 1;
  options.gameDiff ??= "easy";
  return options;
}

function gameSettingsWithDefaultParams(gameSpeed = 1, gameDiff = "easy") {
  return { gameSpeed, gameDiff };
}

gameSettingsWithNullish({ gameSpeed: null, gameDiff: null }); // => {gameSpeed: 1, gameDiff: 'easy'}
gameSettingsWithDefaultParams(undefined, null); // => {gameSpeed: 1, gameDiff: null}
复制代码

上述函数处理空值的方式有一个值得注意的区别。默认参数将用空参数(这里的空参数,只能是 undefined)覆盖默认值,空赋值运算符将不会。

默认参数和空赋值都不会覆盖未定义的值。

const getKey = () => {
  return "somekey";
};
let userDetails = { name: "chika", age: 5, room: 10 };
userDetails.key ??= getKey();
console.log(userDetails.key);

//output : "somekey"
复制代码

数字分隔符

提出原因:

此功能使开发人员可以通过在数字组之间创建视觉分隔来使其数字文字更具可读性。

大数字文字很难使人眼快速解析,尤其是当数字重复很长时。 这会损害获得正确值/数量级的能力。

比如

1000000000; // Is this a billion? a hundred millions? Ten millions?
101475938.38; // what scale is this? what power of 10?
复制代码

因此,可以使用使用下划线(_,U + 005F)作为分隔符.有助于提高数字文字(整数和浮点数)的可读性(在 JS 中,无论如何都是浮点数)

1_000_000_000; // 十亿
101_475_938.38; // 亿万

const amount = 12345_00; // 1234500
const amount = 123_4500; // 1234500
const amount = 1_234_500; // 1,234,500

0.000_001; // 百万分之一
1e10_000; // 10^10000

//
const binary_literals = 0b1010_0001_1000_0101;
const hex_literals = 0xa0_b0_c0;
//
const bigInt_literals = 1_000_000_000_000n;
//
const octal_literal = 0o1234_5670;
复制代码

最后

文章浅陋,欢迎各位看官评论区留下的你的见解!

觉得有收获的同学欢迎点赞,关注一波!

good

往期文章

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享