>[success] # ES12 -- 数字分隔符 -- Numeric literal separator 1. 为了提高大数字的可读性,现在可以用`_`作为数字的分隔符: ~~~ const num = 1_000_000_000 // 1000000000 // 小数 0.000_001 // 科学计数法 1e10_000 ~~~ 2. 数值分隔符有几个使用注意点。 * 不能放在数值的最前面(leading)或最后面(trailing)。 * 不能两个或两个以上的分隔符连在一起。 * 小数点的前后不能有分隔符。 * 科学计数法里面,表示指数的`e`或`E`前后不能有分隔符。 下面的写法都会报错。 ~~~js // 全部报错 3_.141 3._141 1_e12 1e_12 123__456 _1464301 1464301_ ~~~ >[success] # 逻辑运算符和赋值表达式(&&=,||=,??=) 1. 逻辑与赋值 **x &&= y**等效于 **x && (x = y)**; ~~~ let a = 1 let b = 0 a &&= 2 // a && a = 2 console.log(a) // 2 b &&= 2 // b && b=2 console.log(b) // 0 ~~~ 2. 逻辑或赋值(`x ||= y`)运算仅在 `x` 为false时赋值。`x ||= y` 等同于:**x || (x = y);** ~~~ const a = { duration: 50, title: '' } a.duration ||= 10 // a.duration || a.duration = 10 console.log(a.duration) // 50 a.title ||= 'title is empty.' // a.title || a.title ='title is empty.' console.log(a.title) // "title is empty" ~~~ 3. 逻辑空赋值运算符 (`x ??= y`) 仅在 `x` 是  (`null` 或 `undefined`) 时对其赋值。8**`x ??= y` 等价于: x ?? (x = y);** ~~~ function config(options) { options.duration ??= 100; options.speed ??= 25; return options; } config({ duration: 125 }); // { duration: 125, speed: 25 } config({}); // { duration: 100, speed: 25 } const a = { duration: 50 }; a.duration ??= 10; console.log(a.duration); // 50 a.speed ??= 25; console.log(a.speed); // 25 ~~~ >[success] # ES12 -- String.prototype.replaceAll() 1. replaceAll() 方法返回一个新字符串 ~~~ 'aabbcc'.replaceAll('b', '.'); // 'aa..cc' ~~~ >[success] # ES12 -- Promise.any 1. **Promise.any()** 可用于以并行和竞争方式执行独立的异步操作,以获取任何第一个完成的 promise 的值。**简单的说返回最先成功状态的promise** 2. 当遇到失败时候就是Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束,当然期间有一个成功的也结束 ~~~ const promise1 = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve("promise1"); // reject("error promise1 "); }, 3000); }); }; const promise2 = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve("promise2"); // reject("error promise2 "); }, 1000); }); }; const promise3 = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve("promise3"); // reject("error promise3 "); }, 2000); }); }; Promise.any([promise1(), promise2(), promise3()]) .then((first) => { // 只要有一个请求成功 就会返回第一个请求成功的 console.log(first); // 会返回promise2 }) .catch((error) => { // 所有三个全部请求失败 才会来到这里 console.log("error", error); }); ~~~ >[success] # ES12 -- FinalizationRegistry 1. `FinalizationRegistry `提供了这样的一种方法:当一个在注册表中注册的对象被回收时,请求在某个时间点上调用一个清理回调。(清理回调有时被称为 finalizer ) 2. 通过调用register方法,注册任何你想要清理回调的对象,传入该对象和所含的值 >[danger] ##### 案例 * 下面 obj1 obj2 obj3 即使被赋值为null 但是因为arr 一直在引用所以一直没有进入`FinalizationRegistry ` 回调中 ~~~ const register = new FinalizationRegistry((value) => { console.log('销毁回调' + value) }) // 1.Weak Reference(弱引用)和Strong Reference(强引用) let obj1 = { name: '123' } let obj2 = { name: 'kobe' } let obj3 = { name: 'jame' } register.register(obj1, '销毁标记') let arr = [obj1, obj2, obj3] obj1 = null obj2 = null obj3 = null ~~~ * 在一段时间后打印了信息**销毁回调销毁标记** ,因为WeakSet是弱引用如果被销毁就跟着一起清空 ~~~ let obj1 = { name: '123' } let obj2 = { name: 'kobe' } let obj3 = { name: 'jame' } register.register(obj1, '销毁标记') const set = new WeakSet() set.add(obj1) set.add(obj2) set.add(obj3) obj1 = null obj2 = null obj3 = null ~~~ >[success] # ES12 -- WeakRefs 1. 如果我们希望是一个弱引用的话,可以使用WeakRef 2. 通过new WeakRefs 包裹弱引用对象创建,想获取弱引用包裹对象值需要**deref**调用 ~~~ const myWeakRef = new WeakRef({ name: '123', year: '25' }) myWeakRef.deref() // => { name: '123', year: '25' } myWeakRef.deref().name // => '123' ~~~ >[danger] ##### 案例 * 没有使用弱引用 此时因为b 引用了a 不会触发FinalizationRegistry销毁 ~~~ const r = new FinalizationRegistry((val) => { console.log('销毁') }) let a = { name: 1 } const b = a r.register(a) a = null ~~~ * 使用了弱引用 此时会触发`FinalizationRegistry` ~~~ const r = new FinalizationRegistry((val) => { console.log('销毁') }) let a = { name: 1 } const b = new WeakRef(a) r.register(a) a = null ~~~ * 注说明 **myWeakRef** mdn 不建议使用 [mdn WeakRef](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef)