6

该来的还是来了,盘点 ES12 中有新特性!

 3 years ago
source link: https://segmentfault.com/a/1190000040698866
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

作者:KUMAR HARSH
译者:前端小智
来源:blog

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

今天主要介绍一下 ECMAScript 2021(ES12)的一部分的 JS 功能。

  1. 逻辑赋值操作符
  2. 数字分隔符(1_000)
  3. Promise.any 与 AggregateError
  4. String.prototype.replaceAll
  5. WeakRefs 与 FinalizationRegistry 对象

逻辑赋值操作符

逻辑赋值操作符将逻辑操作(&&||??)与赋值表达式组合在一起。

x ||= y;
x || (x = y);

x &&= y;
x && (x = y);


x ??= y;
x ?? (x = y);

带有&&的逻辑赋值操作符

let x = 1;
let y = 2;
x &&= y;
console.log(x); // 2

x &&= y 等价于 x && (x = y)

或者等价于

if(x) {
  x = y
}

因为x是一个真值,所以它被赋值为y,即2

带有||的逻辑赋值操作符

let x = 1;
let y = 2;
x ||= y;
console.log(x); // 1

x ||= y 等价于 x || (x = y)

这意味着赋值操作只在x为虚值时才会发生。在我们的代码中,x包含1,这是一个真值,因此,赋值不会发生。这就是我们的代码在控制台中打印1的原因。

const updateID = user => {

  // 我们可以这样做
  if (!user.id) user.id = 1

  // 或者这样
  user.id = user.id || 1

  // 或者这样
  user.id ||= 1
}

带有??的逻辑赋值操作符

?? 在 JS 中专门检查一个值是否为 nullundefined

let a;
let b = a ?? 5;
console.log(b); // 5

在第二行,let b = a ?? 5,如果a的值为nullundefined??求值并赋值给b

现在考虑??==

let x;
let y = 2;
x ??= y;
console.log(x); // 2

x ??= y 等价于 x = x ?? (x=y)

数字分隔符

它允许我们在数字之间添加下划线(_)字符,使数字更具可读性。

const num = 100000000

被0的数量所迷惑

分隔符解决这个问题:

const num = 100_000_000

分隔符可以用于数字的整数部分和小数部分。

const num = 1_000_000.123_456

分隔符不仅可以用在整数和浮点数中,也可以用在二进制、十六进制、八进制字面量中。

分隔符也适用于BigInt数字。

const trillion = 1000_000_000_000n;
console.log(trillion.toString()); // "1000000000000"

分隔符只是为了可读性。所以,它可以放在数字内的任何地方。

const amount = 178_00; // 00 after _ for cents.

Promise.any 与 AggregateError

Promise.any()返回第一个完成的promise的值。如果所有传递给Promise.any()作为参数(作为数组)的Promise都被拒绝,则抛出一个"AggregateError"异常。

AggregateError`是一个新的Error子类,它对单个错误进行分组。每个AggregateError实例都包含一个对异常数组的引用。

考虑下面例子:

下面我们有3个 promise,它们是随机的。

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("A"), Math.floor(Math.random() * 1000));
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("B"), Math.floor(Math.random() * 1000));
});
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("C"), Math.floor(Math.random() * 1000));
});

p1, p2p3中,最先的完成的的由Promise.any()执行。

(async function() {
  const result = await Promise.any([p1, p2, p3]);
  console.log(result); // 打印 "A", "B" 或者 "C"
})();

如果所有的 promise 都失败了?在这种情况下,Promise.any()抛出AggregateError异常。
我们需要捕获它:

const p = new Promise((resolve, reject) => reject());

try {
  (async function() {
    const result = await Promise.any([p]);
    console.log(result);
  })();
} catch(error) {
  console.log(error.errors);

为了演示的目的,在Promise.any()中我们只能它一个 promise。而这个 promise 是失败的。上述代码在控制台中记录了以下错误。

image.png

String.prototype.replaceAll 方法

String.prototype.replaceAll()允许我们用一个不同的值替换字符串中的所有子串实例,而不需要使用全局正则表达式。

目前,JavaScript字符串有一个replace()方法。它可以用来用另一个字符串替换一个字符串。

const str = "Backbencher sits at the Back";
const newStr = str.replace("Back", "Front");
console.log(newStr); // "Frontbencher sits at the Back"

如果输入模式是一个字符串,replace()方法只替换第一次出现的内容。这就是为什么在代码中,"Back"的第二次出现没有被替换。

只有将模式作为正则表达式提供时,才能进行完全替换。

const str = "Backbencher sits at the Back";
const newStr = str.replace(/Back/g, "Front");
console.log(newStr); // "Frontbencher sits at the Front"

我们来看另一个例子

const strWithPlus = '++'
const strWithComma = strWithPlus.replace(/+/g, ', ')
// , , 

这种方法需要使用正则表达式。然而,复杂的正则表达式往往是错误的来源。(没有人喜欢RegEx 😬)

还有另一种方法是使用String.prototype.split()Array.prototype.join()方法

const strWithPlus = '++'
const strWithComma = strWithPlus.split('+').join(', ')
// , , 

这种方法避免使用正则表达式,但是必须将字符串拆分为单独的部分(单词),将其转换为一个数组,然后将数组元素连接为一个新字符串。

string.prototype.replaceAll()解决了这些问题,并为全局替换子串提供了简单而方便的方式:

const strWithPlus = '++'
const strWithComma = strWithPlus.replaceAll('+', ', ')
// , ,

注意:如果使用全局正则表达式作为查找值,那么replacereplaceAll的行为是一样的。

WeakRefs 与 FinalizationRegistry 对象

WeakRef 是弱引用的意思。弱引用的主要用途是实现大型对象的缓存或映射。在这种情况下,我们不希望长期保留大量的内存来保存这种很少使用的缓存或映射。我们可以让内存很快被垃圾回收,以后如果我们再次需要它,我们可以生成一个新的缓存。

JS 是会自动垃圾收集。如果一个变量不再可达,JS 垃圾收集器将自动删除它。你可以在MDN中阅读更多关于 JS 垃圾收集的内容。

WeaseRefs(弱引用)提供了两个新功能:

  • 使用WeakRef类创建对对象的弱引用
  • 使用FinalizationRegistry类在垃圾收集之后运行自定义收集器

简而言之,WeakRef允许我们创建对象的弱引用,这些对象是另一个对象的属性值,而finalizers可以用来,除其他外,移除对被垃圾收集器 "清理"过的对象的引用。

在创建使用内置缓存的记忆化(memoization)函数时,如果缓存中存在传递给函数的参数的计算值,这种技术可能很有用(前提是对象被用作缓存对象的属性值,以及它们随后被删除的风险),以防止重复执行函数。

在构建内联缓存时

  • 如果没有内存泄漏的风险,那么使用 Map
  • 当使用可以随后删除对象的键时,使用 WeakMap
  • 当使用可以随后删除的值对象时,请将MapWeakRef结合使用

提案中最后一个例子:

function makeWeakCached(f) {
  const cache = new Map()
  return key => {
    const ref = cache.get(key)
    if (ref) {
      //     
      const cached = ref.deref()
      if (cached !== undefined) return cached;
    }

    const fresh = f(key)
    //    ( )
    cache.set(key, new WeakRef(fresh))
    return fresh
  };
}

const getImageCached = makeWeakCached(getImage);
  • WeakRef构造函数接受一个参数,该参数必须是一个对象,并返回对该对象的弱引用
  • WeakRef 实例的deref方法返回两个值中的一个。

在内置缓存的情况下,finalizer被设计为在一个值对象被垃圾收集器销毁后完成清理过程,或者更简单地说,删除对这样一个对象的弱引用。

function makeWeakCached(f) {
  const cache = new Map()
  //    -   
  const cleanup = new FinalizationRegistry(key => {
    const ref = cache.get(key)
    if (ref && !ref.deref()) cache.delete(key)
  })

  return key => {
    const ref = cache.get(key)
    if (ref) {
      const cached = ref.deref()
      if (cached !== undefined) return cached
    }

    const fresh = f(key)
    cache.set(key, new WeakRef(fresh))
    //      ( )
    cleanup.register(fresh, key)
    return fresh
  }
}

const getImageCached = makeWeakCached(getImage);

~完,我是小智,持续咳嗽中,我要去休息了,记录点赞关注,发财致富哦。


原文:https://dev.to/cenacr007_hars...

文章每周持续更新,可以微信搜索【大迁世界 】第一时间阅读,回复【福利】有多份前端视频等着你,本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,欢迎Star。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK